Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Getting RecursionError when Jira servers return 401 #681

Closed
pkkid opened this issue Aug 31, 2018 · 14 comments · Fixed by #1201
Closed

Getting RecursionError when Jira servers return 401 #681

pkkid opened this issue Aug 31, 2018 · 14 comments · Fixed by #1201

Comments

@pkkid
Copy link

pkkid commented Aug 31, 2018

Getting RecursionError: maximum recursion depth exceeded in comparison when getting 401 error codes from Jira using JiraCookieAuth. This looks due to the handle_401 register_hook being passed to the request module in client.py:221. The handle looks like it simply retries the request, but has no mechanism in place to prevent it from retying indefinitely, thus the recursion error.

Commenting out the line request.register_hook('response', self.handle_401) in the JiraAuthCookie class still shows 3 retires to occuring with a pause between each retry. It also stops the RecursionError error from happening, and I assume thrashes the Jira servers much less.

Python 3.5.3
Jira Client: jira-2.0.1.dev17
Communicating with Jira Cloud

Stack Trace

... (many many iterations of the following) ...
  File "/usr/local/lib/python3.5/dist-packages/requests/sessions.py", line 559, in post
    return self.request('POST', url, data=data, json=json, **kwargs)
  File "/usr/local/lib/python3.5/dist-packages/requests/sessions.py", line 512, in request
    resp = self.send(prep, **send_kwargs)
  File "/usr/local/lib/python3.5/dist-packages/requests/sessions.py", line 629, in send
    r = dispatch_hook('response', hooks, r, **kwargs)
  File "/usr/local/lib/python3.5/dist-packages/requests/hooks.py", line 31, in dispatch_hook
    _hook_data = hook(hook_data, **kwargs)
  File "/usr/local/lib/python3.5/dist-packages/jira/client.py", line 202, in handle_401
    self.init_session()
  File "/usr/local/lib/python3.5/dist-packages/jira/client.py", line 218, in init_session
    self.start_session()
  File "/usr/local/lib/python3.5/dist-packages/jira/client.py", line 232, in start_session
    self._get_session(self.__auth)
  File "/usr/local/lib/python3.5/dist-packages/jira/client.py", line 2459, in session
    r = self._session.post(url, data=json.dumps(authentication_data))
  File "/usr/local/lib/python3.5/dist-packages/jira/resilientsession.py", line 154, in post
    return self.__verb('POST', url, **kwargs)
  File "/usr/local/lib/python3.5/dist-packages/jira/resilientsession.py", line 125, in __verb
    response = method(url, timeout=self.timeout, **kwargs)
  File "/usr/local/lib/python3.5/dist-packages/requests/sessions.py", line 559, in post
    return self.request('POST', url, data=data, json=json, **kwargs)
  File "/usr/local/lib/python3.5/dist-packages/requests/sessions.py", line 512, in request
    resp = self.send(prep, **send_kwargs)
  File "/usr/local/lib/python3.5/dist-packages/requests/sessions.py", line 629, in send
    r = dispatch_hook('response', hooks, r, **kwargs)
  File "/usr/local/lib/python3.5/dist-packages/requests/hooks.py", line 31, in dispatch_hook
    _hook_data = hook(hook_data, **kwargs)
  File "/usr/local/lib/python3.5/dist-packages/jira/client.py", line 202, in handle_401
    self.init_session()
  File "/usr/local/lib/python3.5/dist-packages/jira/client.py", line 218, in init_session
    self.start_session()
  File "/usr/local/lib/python3.5/dist-packages/jira/client.py", line 232, in start_session
    self._get_session(self.__auth)
  File "/usr/local/lib/python3.5/dist-packages/jira/client.py", line 2459, in session
    r = self._session.post(url, data=json.dumps(authentication_data))
  File "/usr/local/lib/python3.5/dist-packages/jira/resilientsession.py", line 154, in post
    return self.__verb('POST', url, **kwargs)
  File "/usr/local/lib/python3.5/dist-packages/jira/resilientsession.py", line 125, in __verb
...SNIP...
@ssorgl
Copy link

ssorgl commented Sep 26, 2018

I am seeing the same issue communicating with a JIRA Server instance (instead of Jira Cloud).

But it only goes into this for me when I call

jira = JIRA(server=server, auth=(user, pw))

if instead I call

jira = JIRA(server=server)
issue = jira.issue('VALID-1')

The 401 is flagged as Got recoverable error and it tries again (which fails as it is not logged in)

@pkkid
Copy link
Author

pkkid commented Sep 26, 2018

When I stopped using basic auth and switched to using oAuth, all these issues went away. It was a pain to setup authentication the first time, but it helped 100%.

@ssorgl
Copy link

ssorgl commented Sep 26, 2018

I figured out my 401 error - so no longer imacted by this. But it is still a bug ;)

@rsvancara
Copy link

I figured out my 401 error - so no longer imacted by this. But it is still a bug ;)

Can you elaborate on your solution to the 401 issue more @ssorgl

@ssorgl
Copy link

ssorgl commented Sep 28, 2018

@rsvancara - that was easy: provide the correct credentials! :) Once I realized that it was getting a valid 401, I re-examined my credentials and realized I had not provided the correct string for the user!

@LatvianPython
Copy link

Getting the same error when providing incorrect credentials in a similar way as ssorgl did.
jira = JIRA(server=server, auth=(user, pw))

Right now one has to handle a RecursionError when providing incorrect credentials.

Could this be changed to return a JIRAError with the appropriate 401 status code?

@ZbigniewRA
Copy link

Please note that cookie-based authentication is now being removed from Jira API.
See here: https://developer.atlassian.com/cloud/jira/platform/deprecation-notice-basic-auth-and-cookie-based-auth/

So instead of fixing this bug this feature could be removed altogether (if backwards compatibility is not a concern).

@ssorgl
Copy link

ssorgl commented Sep 2, 2019

I will have to try it out to verify that this is not going to be an issue using and API Token (one of the recommended replacement methods). If I read correctly, the client call will go from:
jira = JIRA(server=server, auth=(user, pw))
to
jira = JIRA(server=server, auth=(user, token))

Has someone tested that not providing the correct credentials (which would still result in the same 401 error from the server I believe) does not just end up in the same recursion error? I suspect it would (same method call, and I believe the same error response from server), but have not had time to test yet.

@ZbigniewRA
Copy link

Actually I think that basic auth should be used instead.
I have verified that changing:

jira = JIRA(server=server, auth=(user, pw))

to:

jira = JIRA(server=server, basic_auth=(user, token))

works fine.
(I use that only through HTTPS.)

@stale
Copy link

stale bot commented Dec 1, 2019

This issue has been automatically marked as stale because it has not had recent activity. It will be closed if no further activity occurs. Thank you for your contributions. You way want to consider using the Sponsor button in order to persuade someone to address it.

@stale stale bot added the stale Ticket that is likely to go nowhere and that will be closed soon label Dec 1, 2019
@Markimedes
Copy link

I've noted this issue in the latest version. It is causing an issue because the plugin attempts to login hundreds of times until the account is locked.

@stale stale bot removed the stale Ticket that is likely to go nowhere and that will be closed soon label Dec 4, 2019
@rsvancara
Copy link

Thanks!

@suederat
Copy link

suederat commented May 12, 2020

recursion restriction needs to be added to handle_401, because simply resending w/o reservation is bad. I would suggest we get a sha of the request and cache it with a count, clear the retry_cache before sending new requests and all should be good

init

`
def __init__():
    self.retry_cache = collections.Counter()
`

verification/usage:

`
def handle_401(self, request):
    retry_key = id(request)
    if retry_key in self.retry_cache and self.retry_cache[retry_key] > defaults.max_retries:
        raise NotAuthorized('please check credentials')
    self.retry_cache[retry_key] += 1
    ...
`

@smathema
Copy link

smathema commented Nov 14, 2020

The fix could be to passing 'self._session.max_retries' to JIRA._create_cookie_auth() function that could be used by JiraCookieAuth(), so JiraCookieAuth.handle_401() doesn't happen forever like it does now until we see 'RecursionError: maximum recursion depth exceeded in comparison', which is same concept as @suederat is suggesting

@adehad adehad linked a pull request Nov 4, 2021 that will close this issue
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging a pull request may close this issue.

9 participants