Skip to content

Commit be2604c

Browse files
committed
Add Session.changeSessionId
1 parent 2aa71ff commit be2604c

File tree

29 files changed

+576
-169
lines changed

29 files changed

+576
-169
lines changed

docs/src/test/java/docs/IndexDocTests.java

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -50,7 +50,7 @@ public class IndexDocTests {
5050

5151
@Test
5252
public void repositoryDemo() {
53-
RepositoryDemo<Session> demo = new RepositoryDemo<>();
53+
RepositoryDemo<MapSession> demo = new RepositoryDemo<>();
5454
demo.repository = new MapSessionRepository();
5555

5656
demo.demo();
@@ -82,7 +82,7 @@ public void demo() {
8282

8383
@Test
8484
public void expireRepositoryDemo() {
85-
ExpiringRepositoryDemo<Session> demo = new ExpiringRepositoryDemo<>();
85+
ExpiringRepositoryDemo<MapSession> demo = new ExpiringRepositoryDemo<>();
8686
demo.repository = new MapSessionRepository();
8787

8888
demo.demo();

samples/misc/hazelcast/src/main/java/sample/Initializer.java

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -34,7 +34,6 @@
3434
import org.springframework.session.MapSession;
3535
import org.springframework.session.MapSessionRepository;
3636
import org.springframework.session.Session;
37-
import org.springframework.session.SessionRepository;
3837
import org.springframework.session.web.http.SessionRepositoryFilter;
3938

4039
@WebListener
@@ -48,8 +47,8 @@ public void contextInitialized(ServletContextEvent sce) {
4847
this.instance = createHazelcastInstance();
4948
Map<String, Session> sessions = this.instance.getMap(SESSION_MAP_NAME);
5049

51-
SessionRepository<Session> sessionRepository = new MapSessionRepository(sessions);
52-
SessionRepositoryFilter<Session> filter = new SessionRepositoryFilter<>(
50+
MapSessionRepository sessionRepository = new MapSessionRepository(sessions);
51+
SessionRepositoryFilter<? extends Session> filter = new SessionRepositoryFilter<>(
5352
sessionRepository);
5453

5554
Dynamic fr = sce.getServletContext().addFilter("springSessionFilter", filter);

spring-session-core/src/main/java/org/springframework/session/MapReactorSessionRepository.java

Lines changed: 12 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -39,7 +39,7 @@
3939
* @author Rob Winch
4040
* @since 2.0
4141
*/
42-
public class MapReactorSessionRepository implements ReactorSessionRepository<Session> {
42+
public class MapReactorSessionRepository implements ReactorSessionRepository<MapSession> {
4343
/**
4444
* If non-null, this value is used to override
4545
* {@link Session#setMaxInactiveInterval(Duration)}.
@@ -80,7 +80,7 @@ public MapReactorSessionRepository(Session... sessions) {
8080
}
8181
this.sessions = new ConcurrentHashMap<>();
8282
for (Session session : sessions) {
83-
this.performSave(session);
83+
this.performSave(new MapSession(session));
8484
}
8585
}
8686

@@ -96,7 +96,7 @@ public MapReactorSessionRepository(Iterable<Session> sessions) {
9696
}
9797
this.sessions = new ConcurrentHashMap<>();
9898
for (Session session : sessions) {
99-
this.performSave(session);
99+
this.performSave(new MapSession(session));
100100
}
101101
}
102102

@@ -110,15 +110,19 @@ public void setDefaultMaxInactiveInterval(int defaultMaxInactiveInterval) {
110110
this.defaultMaxInactiveInterval = Integer.valueOf(defaultMaxInactiveInterval);
111111
}
112112

113-
public Mono<Void> save(Session session) {
113+
public Mono<Void> save(MapSession session) {
114114
return Mono.fromRunnable(() -> performSave(session));
115115
}
116116

117-
private void performSave(Session session) {
117+
private void performSave(MapSession session) {
118+
if (!session.getId().equals(session.getOriginalId())) {
119+
this.sessions.remove(session.getOriginalId());
120+
session.setOriginalId(session.getId());
121+
}
118122
this.sessions.put(session.getId(), new MapSession(session));
119123
}
120124

121-
public Mono<Session> findById(String id) {
125+
public Mono<MapSession> findById(String id) {
122126
return Mono.defer(() -> {
123127
Session saved = this.sessions.get(id);
124128
if (saved == null) {
@@ -136,9 +140,9 @@ public Mono<Void> delete(String id) {
136140
return Mono.fromRunnable(() -> this.sessions.remove(id));
137141
}
138142

139-
public Mono<Session> createSession() {
143+
public Mono<MapSession> createSession() {
140144
return Mono.defer(() -> {
141-
Session result = new MapSession();
145+
MapSession result = new MapSession();
142146
if (this.defaultMaxInactiveInterval != null) {
143147
result.setMaxInactiveInterval(
144148
Duration.ofSeconds(this.defaultMaxInactiveInterval));

spring-session-core/src/main/java/org/springframework/session/MapSession.java

Lines changed: 23 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -52,6 +52,7 @@ public final class MapSession implements Session, Serializable {
5252
public static final int DEFAULT_MAX_INACTIVE_INTERVAL_SECONDS = 1800;
5353

5454
private String id;
55+
private String originalId;
5556
private Map<String, Object> sessionAttrs = new HashMap<>();
5657
private Instant creationTime = Instant.now();
5758
private Instant lastAccessedTime = this.creationTime;
@@ -65,9 +66,10 @@ public final class MapSession implements Session, Serializable {
6566
* Creates a new instance with a secure randomly generated identifier.
6667
*/
6768
public MapSession() {
68-
this(UUID.randomUUID().toString());
69+
this(generateId());
6970
}
7071

72+
7173
/**
7274
* Creates a new instance with the specified id. This is preferred to the default
7375
* constructor when the id is known to prevent unnecessary consumption on entropy
@@ -77,6 +79,7 @@ public MapSession() {
7779
*/
7880
public MapSession(String id) {
7981
this.id = id;
82+
this.originalId = id;
8083
}
8184

8285
/**
@@ -90,6 +93,7 @@ public MapSession(Session session) {
9093
throw new IllegalArgumentException("session cannot be null");
9194
}
9295
this.id = session.getId();
96+
this.originalId = this.id;
9397
this.sessionAttrs = new HashMap<>(
9498
session.getAttributeNames().size());
9599
for (String attrName : session.getAttributeNames()) {
@@ -115,6 +119,20 @@ public String getId() {
115119
return this.id;
116120
}
117121

122+
String getOriginalId() {
123+
return this.originalId;
124+
}
125+
126+
void setOriginalId(String originalId) {
127+
this.originalId = originalId;
128+
}
129+
130+
public String changeSessionId() {
131+
String changedId = generateId();
132+
setId(changedId);
133+
return changedId;
134+
}
135+
118136
public Instant getLastAccessedTime() {
119137
return this.lastAccessedTime;
120138
}
@@ -188,5 +206,9 @@ public int hashCode() {
188206
return this.id.hashCode();
189207
}
190208

209+
private static String generateId() {
210+
return UUID.randomUUID().toString();
211+
}
212+
191213
private static final long serialVersionUID = 7160779239673823561L;
192214
}

spring-session-core/src/main/java/org/springframework/session/MapSessionRepository.java

Lines changed: 9 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -37,7 +37,7 @@
3737
* @author Rob Winch
3838
* @since 1.0
3939
*/
40-
public class MapSessionRepository implements SessionRepository<Session> {
40+
public class MapSessionRepository implements SessionRepository<MapSession> {
4141
/**
4242
* If non-null, this value is used to override
4343
* {@link Session#setMaxInactiveInterval(Duration)}.
@@ -76,11 +76,15 @@ public void setDefaultMaxInactiveInterval(int defaultMaxInactiveInterval) {
7676
this.defaultMaxInactiveInterval = Integer.valueOf(defaultMaxInactiveInterval);
7777
}
7878

79-
public void save(Session session) {
79+
public void save(MapSession session) {
80+
if (!session.getId().equals(session.getOriginalId())) {
81+
this.sessions.remove(session.getOriginalId());
82+
session.setOriginalId(session.getId());
83+
}
8084
this.sessions.put(session.getId(), new MapSession(session));
8185
}
8286

83-
public Session findById(String id) {
87+
public MapSession findById(String id) {
8488
Session saved = this.sessions.get(id);
8589
if (saved == null) {
8690
return null;
@@ -96,8 +100,8 @@ public void deleteById(String id) {
96100
this.sessions.remove(id);
97101
}
98102

99-
public Session createSession() {
100-
Session result = new MapSession();
103+
public MapSession createSession() {
104+
MapSession result = new MapSession();
101105
if (this.defaultMaxInactiveInterval != null) {
102106
result.setMaxInactiveInterval(
103107
Duration.ofSeconds(this.defaultMaxInactiveInterval));

spring-session-core/src/main/java/org/springframework/session/Session.java

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,12 @@ public interface Session {
3737
*/
3838
String getId();
3939

40+
/**
41+
* Changes the session id. After invoking the {@link #getId()} will return a new identifier.
42+
* @return the new session id which {@link #getId()} will now return
43+
*/
44+
String changeSessionId();
45+
4046
/**
4147
* Gets the Object associated with the specified name or null if no Object is
4248
* associated to that name.

spring-session-core/src/main/java/org/springframework/session/web/http/SessionRepositoryFilter.java

Lines changed: 1 addition & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -18,9 +18,6 @@
1818

1919
import java.io.IOException;
2020
import java.time.Instant;
21-
import java.util.Enumeration;
22-
import java.util.HashMap;
23-
import java.util.Map;
2421

2522
import javax.servlet.FilterChain;
2623
import javax.servlet.ServletContext;
@@ -274,30 +271,7 @@ public String changeSessionId() {
274271
"Cannot change session ID. There is no session associated with this request.");
275272
}
276273

277-
// eagerly get session attributes in case implementation lazily loads them
278-
Map<String, Object> attrs = new HashMap<>();
279-
Enumeration<String> iAttrNames = session.getAttributeNames();
280-
while (iAttrNames.hasMoreElements()) {
281-
String attrName = iAttrNames.nextElement();
282-
Object value = session.getAttribute(attrName);
283-
284-
attrs.put(attrName, value);
285-
}
286-
287-
SessionRepositoryFilter.this.sessionRepository.deleteById(session.getId());
288-
HttpSessionWrapper original = getCurrentSession();
289-
setCurrentSession(null);
290-
291-
HttpSessionWrapper newSession = getSession();
292-
original.setSession(newSession.getSession());
293-
294-
newSession.setMaxInactiveInterval(session.getMaxInactiveInterval());
295-
for (Map.Entry<String, Object> attr : attrs.entrySet()) {
296-
String attrName = attr.getKey();
297-
Object attrValue = attr.getValue();
298-
newSession.setAttribute(attrName, attrValue);
299-
}
300-
return newSession.getId();
274+
return getCurrentSession().getSession().changeSessionId();
301275
}
302276

303277
@Override

spring-session-core/src/test/java/org/springframework/session/MapReactorSessionRepositoryTests.java

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -145,4 +145,32 @@ public void createSessionWhenCustomMaxInactiveIntervalThenCustomMaxInactiveInter
145145
assertThat(session.getMaxInactiveInterval())
146146
.isEqualTo(expectedMaxInterval);
147147
}
148+
149+
@Test
150+
public void changeSessionIdWhenNotYetSaved() {
151+
MapSession createSession = this.repository.createSession().block();
152+
153+
String originalId = createSession.getId();
154+
createSession.changeSessionId();
155+
156+
this.repository.save(createSession).block();
157+
158+
assertThat(this.repository.findById(originalId).block()).isNull();
159+
assertThat(this.repository.findById(createSession.getId()).block()).isNotNull();
160+
}
161+
162+
@Test
163+
public void changeSessionIdWhenSaved() {
164+
MapSession createSession = this.repository.createSession().block();
165+
166+
this.repository.save(createSession).block();
167+
168+
String originalId = createSession.getId();
169+
createSession.changeSessionId();
170+
171+
this.repository.save(createSession).block();
172+
173+
assertThat(this.repository.findById(originalId).block()).isNull();
174+
assertThat(this.repository.findById(createSession.getId()).block()).isNotNull();
175+
}
148176
}

spring-session-core/src/test/java/org/springframework/session/MapSessionRepositoryTests.java

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -66,4 +66,32 @@ public void createSessionCustomDefaultExpiration() {
6666
assertThat(session.getMaxInactiveInterval())
6767
.isEqualTo(expectedMaxInterval);
6868
}
69+
70+
@Test
71+
public void changeSessionIdWhenNotYetSaved() {
72+
MapSession createSession = this.repository.createSession();
73+
74+
String originalId = createSession.getId();
75+
createSession.changeSessionId();
76+
77+
this.repository.save(createSession);
78+
79+
assertThat(this.repository.findById(originalId)).isNull();
80+
assertThat(this.repository.findById(createSession.getId())).isNotNull();
81+
}
82+
83+
@Test
84+
public void changeSessionIdWhenSaved() {
85+
MapSession createSession = this.repository.createSession();
86+
87+
this.repository.save(createSession);
88+
89+
String originalId = createSession.getId();
90+
createSession.changeSessionId();
91+
92+
this.repository.save(createSession);
93+
94+
assertThat(this.repository.findById(originalId)).isNull();
95+
assertThat(this.repository.findById(createSession.getId())).isNotNull();
96+
}
6997
}

spring-session-core/src/test/java/org/springframework/session/MapSessionTests.java

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -134,6 +134,10 @@ public Instant getCreationTime() {
134134
return Instant.EPOCH;
135135
}
136136

137+
public String changeSessionId() {
138+
throw new UnsupportedOperationException();
139+
}
140+
137141
public String getId() {
138142
return "id";
139143
}

spring-session-core/src/test/java/org/springframework/session/web/http/SessionRepositoryFilterTests.java

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -76,9 +76,9 @@ public class SessionRepositoryFilterTests {
7676

7777
private Map<String, Session> sessions;
7878

79-
private SessionRepository<Session> sessionRepository;
79+
private SessionRepository<MapSession> sessionRepository;
8080

81-
private SessionRepositoryFilter<Session> filter;
81+
private SessionRepositoryFilter<MapSession> filter;
8282

8383
private MockHttpServletRequest request;
8484

@@ -422,7 +422,7 @@ public void doFilter(HttpServletRequest wrappedRequest) {
422422
public void doFilterSetsCookieIfChanged() throws Exception {
423423
this.sessionRepository = new MapSessionRepository() {
424424
@Override
425-
public Session findById(String id) {
425+
public MapSession findById(String id) {
426426
return createSession();
427427
}
428428
};
@@ -1256,7 +1256,7 @@ public void doFilter(HttpServletRequest wrappedRequest,
12561256
@SuppressWarnings("unchecked")
12571257
public void doFilterRequestSessionNoRequestSessionNoSessionRepositoryInteractions()
12581258
throws Exception {
1259-
SessionRepository<Session> sessionRepository = spy(new MapSessionRepository());
1259+
SessionRepository<MapSession> sessionRepository = spy(new MapSessionRepository());
12601260

12611261
this.filter = new SessionRepositoryFilter<>(sessionRepository);
12621262

@@ -1283,7 +1283,7 @@ public void doFilter(HttpServletRequest wrappedRequest,
12831283

12841284
@Test
12851285
public void doFilterLazySessionCreation() throws Exception {
1286-
SessionRepository<Session> sessionRepository = spy(new MapSessionRepository());
1286+
SessionRepository<MapSession> sessionRepository = spy(new MapSessionRepository());
12871287

12881288
this.filter = new SessionRepositoryFilter<>(sessionRepository);
12891289

@@ -1299,9 +1299,9 @@ public void doFilter(HttpServletRequest wrappedRequest,
12991299

13001300
@Test
13011301
public void doFilterLazySessionUpdates() throws Exception {
1302-
Session session = this.sessionRepository.createSession();
1302+
MapSession session = this.sessionRepository.createSession();
13031303
this.sessionRepository.save(session);
1304-
SessionRepository<Session> sessionRepository = spy(this.sessionRepository);
1304+
SessionRepository<MapSession> sessionRepository = spy(this.sessionRepository);
13051305
setSessionCookie(session.getId());
13061306

13071307
this.filter = new SessionRepositoryFilter<>(sessionRepository);

0 commit comments

Comments
 (0)