Skip to content

Commit aa4b2f0

Browse files
seonwooj0810jzheaux
authored andcommitted
Prevent re-adding deleted sessions to Redis principal index
RedisSession#saveDelta() unconditionally re-adds the session id to the resolved principal's index set whenever the delta contains the principal/security-context attribute key. RedisIndexedSessionRepository #deleteById() first removes the session id via cleanupPrincipalIndex(), then sets maxInactiveInterval to Duration.ZERO and calls save(session), which invokes saveDelta(). Under SaveMode.ALWAYS, the RedisSession constructor unconditionally copies every current attribute (including the principal-index attribute) into the delta, so saveDelta() always takes the principal-index branch on this path. Since the session's own attributes are untouched by deleteById(), resolveIndexesFor() still resolves the same principal, and saveDelta() re-adds the id to the index set that cleanupPrincipalIndex() had just removed it from. The principal's Redis set (e.g. "spring:session:index:...:<principal>") then keeps growing with ids of sessions that were explicitly invalidated, leaking memory. Guard the re-add with RedisSession#isExpired(), which is already true at this point in deleteById() (maxInactiveInterval is set to Duration .ZERO, not a negative "never expires" value). The unconditional removal of the id from the previous principal's set is left untouched, since removal is always correct regardless of expiration state. Closes gh-1843 Signed-off-by: seonwoo_jung <79202163+seonwooj0810@users.noreply.github.com>
1 parent 01e06a4 commit aa4b2f0

2 files changed

Lines changed: 26 additions & 1 deletion

File tree

spring-session-data-redis/src/main/java/org/springframework/session/data/redis/RedisIndexedSessionRepository.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -913,7 +913,7 @@ private void saveDelta() {
913913
Map<String, String> indexes = RedisIndexedSessionRepository.this.indexResolver.resolveIndexesFor(this);
914914
String principal = indexes.get(PRINCIPAL_NAME_INDEX_NAME);
915915
this.originalPrincipalName = principal;
916-
if (principal != null) {
916+
if (principal != null && !isExpired()) {
917917
String principalRedisKey = getPrincipalKey(principal);
918918
RedisIndexedSessionRepository.this.sessionRedisOperations.boundSetOps(principalRedisKey)
919919
.add(sessionId);

spring-session-data-redis/src/test/java/org/springframework/session/data/redis/RedisIndexedSessionRepositoryTests.java

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -334,6 +334,31 @@ void delete() {
334334
verify(this.redisOperations, never()).boundValueOps(getKey("expires:" + id));
335335
}
336336

337+
// gh-1843
338+
@Test
339+
void deleteWhenSaveModeAlwaysThenPrincipalIndexNotReAdded() {
340+
String principalName = "principal";
341+
MapSession expected = new MapSession();
342+
expected.setLastAccessedTime(Instant.now().minusSeconds(60));
343+
expected.setAttribute(FindByIndexNameSessionRepository.PRINCIPAL_NAME_INDEX_NAME, principalName);
344+
given(this.redisOperations.<String, Object>boundHashOps(anyString())).willReturn(this.boundHashOperations);
345+
given(this.redisOperations.boundSetOps(anyString())).willReturn(this.boundSetOperations);
346+
Map<String, Object> map = map(
347+
RedisIndexedSessionRepository
348+
.getSessionAttrNameKey(FindByIndexNameSessionRepository.PRINCIPAL_NAME_INDEX_NAME),
349+
principalName, RedisSessionMapper.CREATION_TIME_KEY, expected.getCreationTime().toEpochMilli(),
350+
RedisSessionMapper.MAX_INACTIVE_INTERVAL_KEY, (int) expected.getMaxInactiveInterval().getSeconds(),
351+
RedisSessionMapper.LAST_ACCESSED_TIME_KEY, expected.getLastAccessedTime().toEpochMilli());
352+
given(this.boundHashOperations.entries()).willReturn(map);
353+
this.redisRepository.setSaveMode(SaveMode.ALWAYS);
354+
355+
String id = expected.getId();
356+
this.redisRepository.deleteById(id);
357+
358+
verify(this.boundSetOperations, atLeastOnce()).remove(id);
359+
verify(this.boundSetOperations, never()).add(id);
360+
}
361+
337362
@Test
338363
void deleteNullSession() {
339364
given(this.redisOperations.<String, Object>boundHashOps(anyString())).willReturn(this.boundHashOperations);

0 commit comments

Comments
 (0)