Skip to content

Commit b6e8c75

Browse files
fix: handle session cookies with no expiry
1 parent 578bbdd commit b6e8c75

2 files changed

Lines changed: 44 additions & 3 deletions

File tree

‎ibmcloudant/couchdb_session_token_manager.py‎

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -84,6 +84,8 @@ def request_token(self):
8484

8585
return response
8686

87+
_DEFAULT_SESSION_COOKIE_TTL_SECONDS = 24 * 60 * 60
88+
8789
def _save_token_info(self, token_response) -> None:
8890
"""
8991
Decode the access token and save the response from the service to the object's state
@@ -100,6 +102,8 @@ def _save_token_info(self, token_response) -> None:
100102
cookie = next(x for x in self.access_token if x.name == 'AuthSession')
101103
exp = cookie.expires
102104
iat = self._get_current_time()
105+
if exp is None:
106+
exp = iat + self._DEFAULT_SESSION_COOKIE_TTL_SECONDS
103107
self.expire_time = exp
104108
ttl = exp - iat
105109
buffer = ttl * 0.2

‎test/unit/test_couchdb_session_auth.py‎

Lines changed: 40 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@
2525

2626
from ibmcloudant import CouchDbSessionAuthenticator
2727
from ibmcloudant.cloudant_v1 import CloudantV1
28+
from ibmcloudant.couchdb_session_token_manager import CouchDbSessionTokenManager
2829

2930
request = requests.request
3031
request_args = None
@@ -55,9 +56,12 @@ def setUp(self) -> None:
5556

5657
def prepare_for_url(self, url):
5758
def post_session(request):
58-
return (200, {
59-
"Set-Cookie": "AuthSession=" + self.cookie_value + "; Version=1; Expires=" +
60-
self.cookie_expire_time + "; Max-Age=600; Path=/; HttpOnly"},
59+
if self.cookie_expire_time is None:
60+
set_cookie = "AuthSession=" + self.cookie_value + "; Version=1; Path=/; HttpOnly"
61+
else:
62+
set_cookie = ("AuthSession=" + self.cookie_value + "; Version=1; Expires=" +
63+
self.cookie_expire_time + "; Max-Age=600; Path=/; HttpOnly")
64+
return (200, {"Set-Cookie": set_cookie},
6165
json.dumps({"ok": True, "name": "adm", "roles": ["_admin"]}))
6266

6367
responses.add_callback(responses.POST, url + '/_session', post_session)
@@ -70,6 +74,7 @@ def post_session(request):
7074

7175
@responses.activate
7276
def test_header_passing(self):
77+
self.cookie_expire_time = None
7378
self.client.set_default_headers({"yes": "works"})
7479
response = self.client.get_session_information(headers={"foo": "bar"})
7580
self.assertIsNotNone(response)
@@ -86,6 +91,7 @@ def test_header_passing(self):
8691

8792
@responses.activate
8893
def test_disable_ssl_verification_on(self):
94+
self.cookie_expire_time = None
8995
original_http_client = self.client.get_http_client()
9096
mock_session = MockSession()
9197
try:
@@ -98,6 +104,7 @@ def test_disable_ssl_verification_on(self):
98104

99105
@responses.activate
100106
def test_disable_ssl_verification_off(self):
107+
self.cookie_expire_time = None
101108
original_http_client = self.client.get_http_client()
102109
mock_session = MockSession()
103110
try:
@@ -136,6 +143,7 @@ def test_invalid_disable_ssl_verification_type(self):
136143

137144
@responses.activate
138145
def test_cookie_refresh(self):
146+
self.cookie_expire_time = None
139147
self.client.get_session_information()
140148
self.assertEqual(responses.calls[-1].request.headers["Cookie"], "AuthSession=foobar")
141149
self.cookie_value = "bar"
@@ -151,6 +159,7 @@ def test_cookie_refresh(self):
151159

152160
@responses.activate
153161
def test_cookie_expired(self):
162+
self.cookie_expire_time = None
154163
self.client.get_session_information()
155164
self.assertEqual(responses.calls[-1].request.headers["Cookie"], "AuthSession=foobar")
156165
self.cookie_value = "bar"
@@ -161,6 +170,7 @@ def test_cookie_expired(self):
161170

162171
@responses.activate
163172
def test_cookie_not_yet_expired(self):
173+
self.cookie_expire_time = None
164174
self.client.get_session_information()
165175
self.assertEqual(responses.calls[-1].request.headers["Cookie"], "AuthSession=foobar")
166176
self.cookie_value = "bar"
@@ -177,8 +187,35 @@ def test_refresh_time_calculation(self):
177187
self.assertAlmostEqual(self.authenticator.token_manager.refresh_time,
178188
self.authenticator.token_manager._get_current_time() + 8 * 60, delta=3)
179189

190+
@responses.activate
191+
def test_refresh_time_calculation_no_expiry(self):
192+
self.cookie_expire_time = None
193+
self.client.get_session_information()
194+
token_manager = self.authenticator.token_manager
195+
default_ttl = CouchDbSessionTokenManager._DEFAULT_SESSION_COOKIE_TTL_SECONDS
196+
self.assertAlmostEqual(token_manager.expire_time,
197+
token_manager._get_current_time() + default_ttl, delta=3)
198+
self.assertAlmostEqual(token_manager.refresh_time,
199+
token_manager._get_current_time() + default_ttl * 0.8, delta=3)
200+
201+
@responses.activate
202+
def test_cookie_without_expiry(self):
203+
self.cookie_expire_time = None
204+
self.client.get_session_information()
205+
self.assertEqual(responses.calls[-1].request.headers["Cookie"], "AuthSession=foobar")
206+
self.cookie_value = "bar"
207+
self.authenticator.token_manager.refresh_time = 0
208+
self.client.get_session_information()
209+
self.assertEqual(responses.calls[-1].request.headers["Cookie"], "AuthSession=bar")
210+
token_manager = self.authenticator.token_manager
211+
self.assertIsNotNone(token_manager.expire_time)
212+
self.assertIsNotNone(token_manager.refresh_time)
213+
self.assertFalse(token_manager._is_token_expired())
214+
self.assertGreater(token_manager.expire_time, token_manager._get_current_time())
215+
180216
@responses.activate
181217
def test_set_service_url(self):
218+
self.cookie_expire_time = None
182219
self.client.get_session_information()
183220
self.assertEqual(responses.calls[-2].request.url, "http://cloudant.example/_session")
184221
self.assertEqual(responses.calls[-2].request.method, "POST")

0 commit comments

Comments
 (0)