resilient-lib `OAuth2ClientCredentialsSession.update_token` method causes infinite loop
lmahoney1 opened this issue · 0 comments
Description
I was getting the following stack trace after the fn_microsoft_security_graph
integration ran for ~ 1 hour (this integration uses an instance of the resilient-lib
OAuth2ClientCredentialsSession
class to handle authentication / make HTTP requests):
Traceback (most recent call last):
File "/usr/lib64/python3.6/threading.py", line 916, in _bootstrap_inner
self.run()
File "/usr/lib64/python3.6/threading.py", line 864, in run
self._target(*self._args, **self._kwargs)
File "/opt/app-root/lib/python3.6/site-packages/fn_microsoft_security_graph/components/microsoft_security_graph_alerts_integrations.py", line 198, in msg_polling_thread
alert_list = get_alerts(self.options, self.Microsoft_security_graph_helper)
File "/opt/app-root/lib/python3.6/site-packages/fn_microsoft_security_graph/components/microsoft_security_graph_alerts_integrations.py", line 290, in get_alerts
r = ms_graph_helper.ms_graph_session.get(url)
File "/opt/app-root/lib/python3.6/site-packages/requests/sessions.py", line 555, in get
return self.request('GET', url, **kwargs)
File "/opt/app-root/lib/python3.6/site-packages/resilient_lib/components/oauth2_client_credentials_session.py", line 140, in request
self.update_token()
File "/opt/app-root/lib/python3.6/site-packages/resilient_lib/components/oauth2_client_credentials_session.py", line 126, in update_token
self.client_secret, self.scope, self.proxies)
File "/opt/app-root/lib/python3.6/site-packages/resilient_lib/components/oauth2_client_credentials_session.py", line 86, in authenticate
r = self.get_token(token_url, client_id, client_secret, scope, proxies)
File "/opt/app-root/lib/python3.6/site-packages/resilient_lib/components/oauth2_client_credentials_session.py", line 118, in get_token
return self.post(token_url, data=post_data, proxies=proxies)
File "/opt/app-root/lib/python3.6/site-packages/requests/sessions.py", line 590, in post
return self.request('POST', url, data=data, json=json, **kwargs)
File "/opt/app-root/lib/python3.6/site-packages/resilient_lib/components/oauth2_client_credentials_session.py", line 140, in request
self.update_token()
... (the same request -> update_token -> authenticate -> get_token -> post lines were repeated many times)
File "/opt/app-root/lib/python3.6/site-packages/resilient_lib/components/oauth2_client_credentials_session.py", line 140, in request
self.update_token()
File "/opt/app-root/lib/python3.6/site-packages/resilient_lib/components/oauth2_client_credentials_session.py", line 126, in update_token
self.client_secret, self.scope, self.proxies)
File "/opt/app-root/lib/python3.6/site-packages/resilient_lib/components/oauth2_client_credentials_session.py", line 86, in authenticate
r = self.get_token(token_url, client_id, client_secret, scope, proxies)
File "/opt/app-root/lib/python3.6/site-packages/resilient_lib/components/oauth2_client_credentials_session.py", line 118, in get_token
return self.post(token_url, data=post_data, proxies=proxies)
File "/opt/app-root/lib/python3.6/site-packages/requests/sessions.py", line 590, in post
return self.request('POST', url, data=data, json=json, **kwargs)
File "/opt/app-root/lib/python3.6/site-packages/resilient_lib/components/oauth2_client_credentials_session.py", line 139, in request
if self.expiration_time < time.time():
RecursionError: maximum recursion depth exceeded in comparison
After some digging into / debugging the integration code, as well as the resilient-lib OAuth2ClientCredentialsSession
code (and the requests.Session
code, since OAuth2ClientCredentialsSession
inherits from requests.Session
) it appears to me that there's an issue with resilient_lib's
OAuth2ClientCredentialsSession`.
The error happens an hour after running as that's when the initial bearer token we get expires. The next time we try to get graph alerts after the bearer token has expired, the request
method in OAuth2ClientCredentialsSession
identifies that the bearer token is expired and that a new one needs to be retrieved, however this functionality appears to be broken.
Below is the process for retrieving a new bearer token:
OAuth2ClientCredentialsSession.update_token
is calledOAuth2ClientCredentialsSession.authenticate
is calledOAuth2ClientCredentialsSession.get_token
is calledrequests.Session.post
is called (through inheritance) - this method callsself.request
whichOAuth2ClientCredentialsSession
has overwrittenOAuth2ClientCredentialsSession.request
is called - Here's the issue, this method identifies that the bearer token is expired, and starts the process to retrieve a new bearer token againOAuth2ClientCredentialsSession.update_token
is called and the process is repeated until the maximum recursion depth is reached
So the request to renew the bearer token is never sent, and there ends up being an infinite recursion loop.
Describe How to Reproduce
Try to make a request with an instance of resilient-lib.OAuth2ClientCredentialsSession
after the initial bearer token retrieved expires.