Skip to content

Commit e5133ac

Browse files
committed
Modify to handle threads using same account/connection object
1 parent 4e95447 commit e5133ac

2 files changed

Lines changed: 23 additions & 24 deletions

File tree

O365/connection.py

Lines changed: 17 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -581,14 +581,6 @@ def __init__(
581581
"https://login.microsoftonline.com/common/oauth2/nativeclient"
582582
)
583583

584-
# In the event of a response that returned 401 unauthorised this will flag between requests
585-
# that this 401 can be a token expired error. MsGraph is returning 401 when the access token
586-
# has expired. We can not distinguish between a real 401 or token expired 401. So in the event
587-
# of a 401 http error we will first try to refresh the token, set this flag to True and then
588-
# re-run the request. If the 401 goes away we will then set this flag to false. If it keeps the
589-
# 401 then we will raise the error.
590-
#: Indicates if the token has expired. |br| **Type:** bool
591-
self._token_expired_flag: bool = False
592584

593585
@property
594586
def auth_flow_type(self) -> str:
@@ -978,13 +970,14 @@ def _check_delay(self) -> None:
978970
self._previous_request_at = time.time()
979971

980972
def _internal_request(
981-
self, session_obj: Session, url: str, method: str, **kwargs
973+
self, session_obj: Session, url: str, method: str, ignore401: bool, **kwargs
982974
) -> Response:
983975
"""Internal handling of requests. Handles Exceptions.
984976
985977
:param session_obj: a requests Session instance.
986978
:param str url: url to send request to
987979
:param str method: type of request (get/put/post/patch/delete)
980+
:param bool ignore401: indicates whether to ignore 401 error or not
988981
:param kwargs: extra params to send to the request api
989982
:return: Response of the request
990983
:rtype: requests.Response
@@ -1043,14 +1036,13 @@ def _internal_request(
10431036
raise e # re-raise exception
10441037
except HTTPError as e:
10451038
# Server response with 4XX or 5XX error status codes
1046-
if e.response.status_code == 401 and self._token_expired_flag is False:
1039+
if e.response.status_code == 401 and ignore401 is True:
10471040
# This could be a token expired error.
10481041
if self.token_backend.token_is_expired(username=self.username):
10491042
# Access token has expired, try to refresh the token and try again on the next loop
10501043
# By raising custom exception TokenExpiredError we signal oauth_request to fire a
10511044
# refresh token operation.
10521045
log.debug(f"Oauth Token is expired for username: {self.username}")
1053-
self._token_expired_flag = True
10541046
raise TokenExpiredError("Oauth Token is expired")
10551047

10561048
# try to extract the error message:
@@ -1103,7 +1095,7 @@ def naive_request(self, url: str, method: str, **kwargs) -> Response:
11031095
# lazy creation of a naive session
11041096
self.naive_session = self.get_naive_session()
11051097

1106-
return self._internal_request(self.naive_session, url, method, **kwargs)
1098+
return self._internal_request(self.naive_session, url, method, ignore401=False **kwargs)
11071099

11081100
def oauth_request(self, url: str, method: str, **kwargs) -> Response:
11091101
"""Makes a request to url using an oauth session.
@@ -1124,18 +1116,22 @@ def oauth_request(self, url: str, method: str, **kwargs) -> Response:
11241116
f"No auth token found. Authentication Flow needed for user {self.username}"
11251117
)
11261118

1119+
# In the event of a response that returned 401 unauthorised the ignore401 flag indicates
1120+
# that the 401 can be a token expired error. MsGraph is returning 401 when the access token
1121+
# has expired. We can not distinguish between a real 401 or token expired 401. So in the event
1122+
# of a 401 http error we will ignore the first time and try to refresh the token, and then
1123+
# re-run the request. If the 401 goes away we can move on. If it keeps the 401 then we will
1124+
# raise the error.
11271125
try:
1128-
return self._internal_request(self.session, url, method, **kwargs)
1126+
return self._internal_request(self.session, url, method, ignore401=True, **kwargs)
11291127
except TokenExpiredError as e:
11301128
# refresh and try again the request!
1131-
try:
1132-
# try to refresh the token and/or follow token backend answer on 'should_refresh_token'
1133-
if self._try_refresh_token():
1134-
return self._internal_request(self.session, url, method, **kwargs)
1135-
else:
1136-
raise e
1137-
finally:
1138-
self._token_expired_flag = False
1129+
1130+
# try to refresh the token and/or follow token backend answer on 'should_refresh_token'
1131+
if self._try_refresh_token():
1132+
return self._internal_request(self.session, url, method, ignore401=False, **kwargs)
1133+
else:
1134+
raise e
11391135

11401136
def get(self, url: str, params: Optional[dict] = None, **kwargs) -> Response:
11411137
"""Shorthand for self.oauth_request(url, 'get')

examples/token_backends.py

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -199,10 +199,13 @@ def should_refresh_token(self, con: Optional[Connection] = None, username: Optio
199199
log.debug(f"Oauth file locked. Sleeping for 2 seconds... retrying {i - 1} more times.")
200200
time.sleep(2)
201201
log.debug("Waking up and rechecking token file for update from other instance...")
202-
# Assume the token has been already updated
202+
# Check if new token has been created.
203203
self.load_token()
204-
# Return False so the connection can update the token access from the backend into the session
205-
return False
204+
if not self.token_is_expired():
205+
log.debug("Token file has been updated in other instance...")
206+
# Return False so the connection can update the token access from the
207+
# backend into the session
208+
return False
206209

207210
# if we exit the loop, that means we were locked out of the file after
208211
# multiple retries give up and throw an error - something isn't right

0 commit comments

Comments
 (0)