2323import org .junit .jupiter .api .Test ;
2424import reactor .core .publisher .Mono ;
2525
26+ import org .springframework .mock .web .server .MockWebSession ;
2627import org .springframework .security .core .Authentication ;
2728import org .springframework .security .core .session .ReactiveSessionInformation ;
2829import org .springframework .security .web .server .authentication .InvalidateLeastUsedServerMaximumSessionsExceededHandler ;
3435import static org .mockito .Mockito .atLeastOnce ;
3536import static org .mockito .Mockito .mock ;
3637import static org .mockito .Mockito .spy ;
38+ import static org .mockito .Mockito .times ;
3739import static org .mockito .Mockito .verify ;
3840import static org .mockito .Mockito .verifyNoMoreInteractions ;
3941
@@ -59,18 +61,21 @@ void handleWhenInvokedThenInvalidatesLeastRecentlyUsedSessions() {
5961 ReactiveSessionInformation session2 = mock (ReactiveSessionInformation .class );
6062 given (session1 .getLastAccessTime ()).willReturn (Instant .ofEpochMilli (1700827760010L ));
6163 given (session2 .getLastAccessTime ()).willReturn (Instant .ofEpochMilli (1700827760000L ));
64+ given (session1 .getSessionId ()).willReturn ("session1" );
6265 given (session2 .getSessionId ()).willReturn ("session2" );
6366 given (session2 .invalidate ()).willReturn (Mono .empty ());
6467
6568 MaximumSessionsContext context = new MaximumSessionsContext (mock (Authentication .class ),
66- List .of (session1 , session2 ), 2 , null );
69+ List .of (session1 , session2 ), 2 , createWebSession () );
6770
6871 this .handler .handle (context ).block ();
6972
7073 verify (session2 ).invalidate ();
7174 verify (session1 ).getLastAccessTime (); // used by comparator to sort the sessions
7275 verify (session2 ).getLastAccessTime (); // used by comparator to sort the sessions
73- verify (session2 ).getSessionId (); // used to invalidate session against the
76+ verify (session1 ).getSessionId ();
77+ verify (session2 , times (2 )).getSessionId (); // used to invalidate session against
78+ // the
7479 // WebSessionStore
7580 verify (this .webSessionStore ).removeSession ("session2" );
7681 verifyNoMoreInteractions (this .webSessionStore );
@@ -90,16 +95,18 @@ void handleWhenMoreThanOneSessionToInvalidateThenInvalidatesAllOfThem() {
9095 given (session2 .invalidate ()).willReturn (Mono .empty ());
9196 given (session1 .getSessionId ()).willReturn ("session1" );
9297 given (session2 .getSessionId ()).willReturn ("session2" );
98+ given (session3 .getSessionId ()).willReturn ("session3" );
9399
94100 MaximumSessionsContext context = new MaximumSessionsContext (mock (Authentication .class ),
95- List .of (session1 , session2 , session3 ), 2 , null );
101+ List .of (session1 , session2 , session3 ), 2 , createWebSession () );
96102 this .handler .handle (context ).block ();
97103
98104 // @formatter:off
99105 verify (session1 ).invalidate ();
100106 verify (session2 ).invalidate ();
101- verify (session1 ).getSessionId ();
102- verify (session2 ).getSessionId ();
107+ verify (session1 , times (2 )).getSessionId ();
108+ verify (session2 , times (2 )).getSessionId ();
109+ verify (session3 ).getSessionId ();
103110 verify (session1 , atLeastOnce ()).getLastAccessTime (); // used by comparator to sort the sessions
104111 verify (session2 , atLeastOnce ()).getLastAccessTime (); // used by comparator to sort the sessions
105112 verify (session3 , atLeastOnce ()).getLastAccessTime (); // used by comparator to sort the sessions
@@ -112,4 +119,33 @@ void handleWhenMoreThanOneSessionToInvalidateThenInvalidatesAllOfThem() {
112119 // @formatter:on
113120 }
114121
122+ @ Test
123+ void handleWhenCurrentSessionIsRegisteredThenDoNotInvalidateCurrentSession () {
124+ ReactiveSessionInformation session1 = mock (ReactiveSessionInformation .class );
125+ ReactiveSessionInformation session2 = mock (ReactiveSessionInformation .class );
126+ MockWebSession currentSession = createWebSession ();
127+ given (session1 .getLastAccessTime ()).willReturn (Instant .ofEpochMilli (1700827760010L ));
128+ given (session2 .getLastAccessTime ()).willReturn (Instant .ofEpochMilli (1700827760000L ));
129+ given (session1 .getSessionId ()).willReturn ("session1" );
130+ given (session2 .getSessionId ()).willReturn (currentSession .getId ());
131+ given (session1 .invalidate ()).willReturn (Mono .empty ());
132+
133+ MaximumSessionsContext context = new MaximumSessionsContext (mock (Authentication .class ),
134+ List .of (session1 , session2 ), 1 , currentSession );
135+
136+ this .handler .handle (context ).block ();
137+
138+ verify (session1 ).invalidate ();
139+ verify (session2 ).getSessionId ();
140+ verify (session1 , times (2 )).getSessionId ();
141+ verify (this .webSessionStore ).removeSession ("session1" );
142+ verifyNoMoreInteractions (this .webSessionStore );
143+ verifyNoMoreInteractions (session2 );
144+ verifyNoMoreInteractions (session1 );
145+ }
146+
147+ private MockWebSession createWebSession () {
148+ return new MockWebSession ();
149+ }
150+
115151}
0 commit comments