From 0ac56011387eecf0015c5eddbd3f146bf91aa7be Mon Sep 17 00:00:00 2001 From: sbasan Date: Thu, 29 Feb 2024 14:42:04 +0100 Subject: [PATCH] fix: jsession expiration detection, jsession cookie persistency --- catalystwan/response.py | 19 ++++++++++++++++--- catalystwan/session.py | 8 +++++--- 2 files changed, 21 insertions(+), 6 deletions(-) diff --git a/catalystwan/response.py b/catalystwan/response.py index c125c3453..2af24f34b 100644 --- a/catalystwan/response.py +++ b/catalystwan/response.py @@ -1,4 +1,6 @@ import re +from datetime import datetime +from email.utils import parsedate_to_datetime from functools import wraps from pprint import pformat from typing import Any, Callable, Dict, Optional, Sequence, Type, TypeVar, Union, cast @@ -134,14 +136,25 @@ class ManagerResponse(Response, APIEndpointClientResponse): def __init__(self, response: Response): self.__dict__.update(response.__dict__) - if not self.cookies.keys(): - self.cookies = self.__parse_set_cookie_from_headers() + self.jsessionid_expired = self._detect_expired_jsessionid() try: self.payload = JsonPayload(response.json()) except JSONDecodeError: self.payload = JsonPayload() - def __parse_set_cookie_from_headers(self) -> RequestsCookieJar: + def _detect_expired_jsessionid(self) -> bool: + """Determines if server sent expired JSESSIONID""" + cookies = self._parse_set_cookie_from_headers() + if (expires := cookies.get("Expires")) and cookies.get("JSESSIONID"): + # get current server time, when not present use local time + # local time might be innacurate but "Expires" is usually set to year 1970 + response_date = self.headers.get("date") + compare_date = parsedate_to_datetime(response_date) if response_date is not None else datetime.now() + if parsedate_to_datetime(expires) <= compare_date: + return True + return False + + def _parse_set_cookie_from_headers(self) -> RequestsCookieJar: """Parses "set-cookie" content from response headers""" jar = RequestsCookieJar() cookies_string = self.headers.get("set-cookie", "") diff --git a/catalystwan/session.py b/catalystwan/session.py index 7d0a2a6db..1b2f82a50 100644 --- a/catalystwan/session.py +++ b/catalystwan/session.py @@ -91,6 +91,7 @@ def create_manager_session( """ session = ManagerSession(url=url, username=username, password=password, port=port, subdomain=subdomain) session.auth = vManageAuth(session.base_url, username, password, verify=False) + if logger: session.logger = logger session.auth.logger = logger @@ -127,7 +128,7 @@ def create_manager_session( session.logger.info( f"Logged to vManage({session.platform_version}) as {username}. The session type is {session.session_type}" ) - + session.cookies.set("JSESSIONID", session.auth.set_cookie.get("JSESSIONID")) return session @@ -208,9 +209,10 @@ def request(self, method, url, *args, **kwargs) -> ManagerResponse: self.logger.error(exception) raise ManagerRequestException(request=exception.request, response=exception.response) - if self.enable_relogin and self.__is_jsession_updated(response): - self.logger.warning("Logging to session again. Reason: JSESSIONID cookie updated by response") + if self.enable_relogin and response.jsessionid_expired: + self.logger.warning("Logging to session again. Reason: expired JSESSIONID detected in response headers") self.auth = vManageAuth(self.base_url, self.username, self.password, verify=False) + self.cookies.set("JSESSIONID", self.auth.set_cookie.get("JSESSIONID")) return self.request(method, url, *args, **kwargs) if response.request.url and "passwordReset.html" in response.request.url: