Skip to content

Commit 4180a25

Browse files
authored
Merge pull request #1152 from RogerSelwyn/threading
Modify to handle threads using same account/connection object
2 parents 1cc3dc3 + cf9354b commit 4180a25

File tree

2 files changed

+26
-24
lines changed

2 files changed

+26
-24
lines changed

O365/connection.py

+20-21
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,17 @@ 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 = False, **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 when it would
981+
indicate that there the token has expired. This is set to 'True' for the
982+
first call to the api, and 'False' for the call that is initiated after a
983+
tpken refresh.
988984
:param kwargs: extra params to send to the request api
989985
:return: Response of the request
990986
:rtype: requests.Response
@@ -1043,14 +1039,13 @@ def _internal_request(
10431039
raise e # re-raise exception
10441040
except HTTPError as e:
10451041
# Server response with 4XX or 5XX error status codes
1046-
if e.response.status_code == 401 and self._token_expired_flag is False:
1042+
if e.response.status_code == 401 and ignore401 is True:
10471043
# This could be a token expired error.
10481044
if self.token_backend.token_is_expired(username=self.username):
10491045
# Access token has expired, try to refresh the token and try again on the next loop
10501046
# By raising custom exception TokenExpiredError we signal oauth_request to fire a
10511047
# refresh token operation.
10521048
log.debug(f"Oauth Token is expired for username: {self.username}")
1053-
self._token_expired_flag = True
10541049
raise TokenExpiredError("Oauth Token is expired")
10551050

10561051
# try to extract the error message:
@@ -1103,7 +1098,7 @@ def naive_request(self, url: str, method: str, **kwargs) -> Response:
11031098
# lazy creation of a naive session
11041099
self.naive_session = self.get_naive_session()
11051100

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

11081103
def oauth_request(self, url: str, method: str, **kwargs) -> Response:
11091104
"""Makes a request to url using an oauth session.
@@ -1124,18 +1119,22 @@ def oauth_request(self, url: str, method: str, **kwargs) -> Response:
11241119
f"No auth token found. Authentication Flow needed for user {self.username}"
11251120
)
11261121

1122+
# In the event of a response that returned 401 unauthorised the ignore401 flag indicates
1123+
# that the 401 can be a token expired error. MsGraph is returning 401 when the access token
1124+
# has expired. We can not distinguish between a real 401 or token expired 401. So in the event
1125+
# of a 401 http error we will ignore the first time and try to refresh the token, and then
1126+
# re-run the request. If the 401 goes away we can move on. If it keeps the 401 then we will
1127+
# raise the error.
11271128
try:
1128-
return self._internal_request(self.session, url, method, **kwargs)
1129+
return self._internal_request(self.session, url, method, ignore401=True, **kwargs)
11291130
except TokenExpiredError as e:
11301131
# 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
1132+
1133+
# try to refresh the token and/or follow token backend answer on 'should_refresh_token'
1134+
if self._try_refresh_token():
1135+
return self._internal_request(self.session, url, method, ignore401=False, **kwargs)
1136+
else:
1137+
raise e
11391138

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

examples/token_backends.py

+6-3
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)