diff --git a/spring-session-data-redis/src/integration-test/java/org/springframework/session/data/redis/RedisIndexedSessionRepositoryITests.java b/spring-session-data-redis/src/integration-test/java/org/springframework/session/data/redis/RedisIndexedSessionRepositoryITests.java index 3b62f128d..e1665aeeb 100644 --- a/spring-session-data-redis/src/integration-test/java/org/springframework/session/data/redis/RedisIndexedSessionRepositoryITests.java +++ b/spring-session-data-redis/src/integration-test/java/org/springframework/session/data/redis/RedisIndexedSessionRepositoryITests.java @@ -1,5 +1,5 @@ /* - * Copyright 2014-2020 the original author or authors. + * Copyright 2014-2021 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. @@ -473,6 +473,60 @@ void findByChangedSecurityPrincipalNameReload() { assertThat(findByPrincipalName.keySet()).containsOnly(toSave.getId()); } + @Test // gh-1791 + void changeSessionIdWhenSessionExpiresThenRemovesAllPrincipalIndexIds() { + RedisSession toSave = this.repository.createSession(); + toSave.setAttribute(SPRING_SECURITY_CONTEXT, this.context); + + this.repository.save(toSave); + String usernameSessionKey = "RedisIndexedSessionRepositoryITests:index:" + INDEX_NAME + ":" + getSecurityName(); + + RedisSession findById = this.repository.findById(toSave.getId()); + String originalFindById = findById.getId(); + + assertThat(this.redis.boundSetOps(usernameSessionKey).members()).contains(originalFindById); + + String changeSessionId = findById.changeSessionId(); + findById.setAttribute(SPRING_SECURITY_CONTEXT, this.context); + + this.repository.save(findById); + + assertThat(this.redis.boundSetOps(usernameSessionKey).members()).contains(changeSessionId); + + String body = "RedisIndexedSessionRepositoryITests:sessions:expires:" + changeSessionId; + String channel = "__keyevent@0__:expired"; + DefaultMessage message = new DefaultMessage(channel.getBytes(StandardCharsets.UTF_8), + body.getBytes(StandardCharsets.UTF_8)); + byte[] pattern = new byte[] {}; + this.repository.onMessage(message, pattern); + + assertThat(this.redis.boundSetOps(usernameSessionKey).members()).isEmpty(); + } + + @Test + void changeSessionIdWhenPrincipalNameChangesThenNewPrincipalMapsToNewSessionId() { + String principalName = "findByChangedPrincipalName" + UUID.randomUUID(); + String principalNameChanged = "findByChangedPrincipalName" + UUID.randomUUID(); + RedisSession toSave = this.repository.createSession(); + toSave.setAttribute(INDEX_NAME, principalName); + + this.repository.save(toSave); + + RedisSession findById = this.repository.findById(toSave.getId()); + String changeSessionId = findById.changeSessionId(); + findById.setAttribute(INDEX_NAME, principalNameChanged); + this.repository.save(findById); + + Map findByPrincipalName = this.repository.findByIndexNameAndIndexValue(INDEX_NAME, + principalName); + assertThat(findByPrincipalName).isEmpty(); + + findByPrincipalName = this.repository.findByIndexNameAndIndexValue(INDEX_NAME, principalNameChanged); + + assertThat(findByPrincipalName).hasSize(1); + assertThat(findByPrincipalName.keySet()).containsOnly(changeSessionId); + } + @Test void changeSessionIdWhenOnlyChangeId() { String attrName = "changeSessionId"; 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 651450421..e1cd731dd 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-2020 the original author or authors. + * Copyright 2014-2021 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. @@ -858,6 +858,11 @@ private void saveChangeSessionId() { catch (NonTransientDataAccessException ex) { handleErrNoSuchKeyError(ex); } + String originalPrincipalRedisKey = getPrincipalKey(this.originalPrincipalName); + RedisIndexedSessionRepository.this.sessionRedisOperations.boundSetOps(originalPrincipalRedisKey) + .remove(this.originalSessionId); + RedisIndexedSessionRepository.this.sessionRedisOperations.boundSetOps(originalPrincipalRedisKey) + .add(sessionId); } this.originalSessionId = sessionId; }