@@ -81,19 +81,29 @@ def test_get_session_invalid_bearer(monkeypatch, client):
8181 assert resp .status_code == 404
8282
8383def test_put_session_extend (client , store , frozen_time ):
84- sid , session = sm .get_current_session ()
84+ # Capture original values before the PUT
85+ before = store .get_session_data ("fake_current_sid" )
86+ old_expires_at = before .expires_at
87+
8588 resp = client .put ("/session" )
8689 assert resp .status_code == 200
87- updated = store .get_session_data (sid )
88- # Expires_at should have been set to frozen_time + ttl
89- assert updated .expires_at == frozen_time + store .ttl
90- # updated_at should match frozen_time
91- assert updated .updated_at == frozen_time
9290
93- def test_put_session_expired (client ):
94- # simulate that refresh_expires_at is in the past
91+ after = store .get_session_data ("fake_current_sid" )
92+
93+ # update_session sets updated_at to time.time() (frozen_time in tests)
94+ assert after .updated_at == pytest .approx (frozen_time , abs = 1 )
95+
96+ # update_session sets expires_at = max(current_expires_at, now + ttl)
97+ expected_expires = max (old_expires_at , frozen_time + store .ttl )
98+ assert after .expires_at == pytest .approx (expected_expires , abs = 1 )
99+
100+
101+ def test_put_session_expired (client , app , monkeypatch ):
95102 sid , sess = sm .get_current_session ()
96- sess .session_metadata .system ["refresh_expires_at" ] = int (time .time ()) - 1
103+ sess .session_metadata .system ["refresh_expires_at" ] = int (time .time ()) + 60
104+ monkeypatch .setattr (sm , "revoke_tokens" , lambda sid , session : None )
105+ with app .app_context ():
106+ app .config ["SESSION_EXPIRY_THRESHOLD" ] = 300
97107 resp = client .put ("/session" )
98108 assert resp .status_code == 401
99109
@@ -118,11 +128,14 @@ def test_put_session_with_refresh_access_token(client,
118128 sess .access_token = "old_access_token"
119129 sess .id_token = "old_id_token"
120130
131+ # Record current expires_at so we can assert the max() behavior
132+ original_expires_at = sess .expires_at
133+
121134 # Stub get_current_session -> (sid, sess)
122135 monkeypatch .setattr (sm ,"get_current_session" , lambda : (sid , sess ))
123136
124137 # Stub out map_session
125- monkeypatch .setattr (store , "map_session" , lambda session_key , session_id : "dummy-map-key" )
138+ monkeypatch .setattr (store , "map_session" , lambda session_key , session_id , ttl : "dummy-map-key" )
126139
127140 # Configure our dummy OIDC client factory in Flask config
128141 class DummyClient :
@@ -154,7 +167,7 @@ def get_client(self, realm, native_client=False):
154167
155168 # Audit events
156169 assert any (ev == "access_token_refreshed" for ev , _ in audit_calls ), audit_calls
157- assert any (ev == "session_extended " for ev , _ in audit_calls ), audit_calls
170+ assert any (ev == "session_updated " for ev , _ in audit_calls ), audit_calls
158171
159172 # Fetch the persisted session from the store
160173 updated = store .get_session_data (sid )
@@ -169,8 +182,10 @@ def get_client(self, realm, native_client=False):
169182 assert meta ["token_expires_at" ] == now + 3600
170183 assert meta ["refresh_expires_at" ] == now + 7200
171184
172- # Finally, ensure update_session bumped the session TTL
173- assert updated .expires_at == pytest .approx (now + store .ttl , abs = 1 )
185+ # update_session should have bumped updated_at and applied max() for expires_at
186+ assert updated .updated_at == pytest .approx (now , abs = 1 )
187+ expected_expires = max (original_expires_at , now + store .ttl )
188+ assert updated .expires_at == pytest .approx (expected_expires , abs = 1 )
174189
175190
176191def test_put_session_with_refresh_access_token_failure (client ,
@@ -193,11 +208,13 @@ def test_put_session_with_refresh_access_token_failure(client,
193208 sess .access_token = "old_access_token"
194209 sess .id_token = "old_id_token"
195210
211+ original_expires_at = sess .expires_at
212+
196213 # Patch get_current_session
197214 monkeypatch .setattr (sm , "get_current_session" , lambda : (sid , sess ))
198215
199216 # Patch map_session
200- monkeypatch .setattr (store , "map_session" , lambda session_key , session_id : "dummy-map-key" )
217+ monkeypatch .setattr (store , "map_session" , lambda session_key , session_id , ttl : "dummy-map-key" )
201218
202219 # Configure dummy client that fails
203220 class DummyFailClient :
@@ -219,7 +236,7 @@ def get_client(self, realm, native_client=False):
219236
220237 # Check audit includes the failure
221238 assert any (ev == "access_token_refresh_failed" for ev , _ in audit_calls ), audit_calls
222- assert any (ev == "session_extended " for ev , _ in audit_calls ), audit_calls
239+ assert any (ev == "session_updated " for ev , _ in audit_calls ), audit_calls
223240
224241 # Fetch stored session
225242 updated = store .get_session_data (sid )
@@ -234,8 +251,10 @@ def get_client(self, realm, native_client=False):
234251 assert meta ["token_expires_at" ] == now - 1
235252 assert meta ["refresh_expires_at" ] == now + 600
236253
237- # But TTL was still bumped by update_session
238- assert updated .expires_at == pytest .approx (now + store .ttl , abs = 1 )
254+ # update_session should have bumped updated_at and applied max() for expires_at
255+ assert updated .updated_at == pytest .approx (now , abs = 1 )
256+ expected_expires = max (original_expires_at , now + store .ttl )
257+ assert updated .expires_at == pytest .approx (expected_expires , abs = 1 )
239258
240259
241260def test_put_session_additional_tokens_refresh (client ,
@@ -250,9 +269,6 @@ def test_put_session_additional_tokens_refresh(client,
250269 threshold = 500
251270
252271 # Prepare a session with four additional token blocks:
253- # - "good" and "fail" are expired by > threshold
254- # - "not_due" is far in the future
255- # - "no_rt" has no refresh_token
256272 sess = copy .deepcopy (base_session )
257273 sess .additional_tokens = {
258274 "good" : {"refresh_token" : "rt_good" , "expires_at" : now - threshold - 1 },
@@ -265,14 +281,16 @@ def test_put_session_additional_tokens_refresh(client,
265281 sess .expires_at = now + 10000
266282
267283 # Stub get_current_session so GET/PUT /session uses our SID and session
268- monkeypatch .setattr (sm ,"get_current_session" , lambda : (sid , sess ))
284+ monkeypatch .setattr (sm , "get_current_session" , lambda : (sid , sess ))
269285
270- # Stub out map_session
271- monkeypatch .setattr (store , "map_session" , lambda session_key , session_id : "dummy-map-key" )
286+ monkeypatch .setattr (store , "map_session" , lambda session_key , session_id , ttl : "dummy-map-key" )
272287
273- # Capture calls to update_session
274- updated = []
275- monkeypatch .setattr (store , "update_session" , lambda s , sd : updated .append ((s , sd )))
288+ # Capture calls to update_session, and make it return (session_key, session_data)
289+ updated_calls = []
290+ def _update_session (s , sd ):
291+ updated_calls .append ((s , sd ))
292+ return ("dummy-map-key" , sd )
293+ monkeypatch .setattr (store , "update_session" , _update_session )
276294
277295 # Provide a DummyClient that succeeds for "rt_good" and raises for "rt_fail"
278296 class DummyClient :
@@ -297,7 +315,6 @@ def get_client(self, realm, native_client=False):
297315
298316 with app .app_context ():
299317 app .config ["TOKEN_EXPIRY_THRESHOLD" ] = 300
300- # Inject our dummy factory
301318 app .config ["OIDC_CLIENT_FACTORY" ] = DummyFactory ()
302319
303320 # Perform the PUT /session
@@ -310,8 +327,8 @@ def get_client(self, realm, native_client=False):
310327 assert "additional_token_refresh_failed" in events , audit_calls
311328
312329 # Only the "good" path should have resulted in update_session
313- assert len (updated ) == 1
314- called_sid , new_sess = updated [0 ]
330+ assert len (updated_calls ) == 1
331+ called_sid , new_sess = updated_calls [0 ]
315332 assert called_sid == sid
316333
317334 # Verify the "good" block was updated correctly
@@ -434,4 +451,4 @@ def test_make_session_response_legacy(app, store, base_session):
434451 assert abs (since_dt .timestamp () - base_session .created_at ) < 1
435452 assert abs (expires_dt .timestamp () - base_session .expires_at ) < 1
436453
437- assert resp ["seconds_remaining" ] == store .get_ttl ("sid123" )
454+ assert resp ["seconds_remaining" ] == store .get_ttl ("sid123" )
0 commit comments