-
Notifications
You must be signed in to change notification settings - Fork 21
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
Concurrency issue in generate_request_header #8
Comments
Thanks a lot for the heads up @mkomitee! |
Hmm, we're at 11 months with no activity from the requests-kerberos folks. I'm considering merging your fix, but wanted to check first - do you have interest in adapting the PR to our (pretty similar) codebase, or should I just do that? |
I think there may be some confusion about ownership, authority, & responsibility for the project. I'm the original author as I submit the original code which was merged into the requests library itself originally. They did some refactoring and split out most of the authentication methods into a separate project. I have the ability to merge it, but I don't think I have the ability to cut a release. I'm also reluctant to merge PRs without someone willing to review it. |
I took a deeper look at the change. If requests-kerberos isn't going to take it (and they don't seem likely to at this point), then we have a bit of a problem with regards to the compat shim. It's pretty difficult for generate_request_header to have different types between the two. I spent some time playing with it and was unable to come up with a solution to the problem of So if you have a patch that preserves the compat shim while fixing the issue, I'd be happy to take that. |
Solves the concurrency issue brought up in pythongssapi/requests-gssapi#8 by passing the context around through the flow instead of storing it in a global dictionary. Inlined authenticate_user() because it didn't do anything more than set the auth header and handle_401() because it became unnecessarily complicated.
Suffer from this one too with weird exceptions. Using a Any chance to have this ported to this module? |
Per #8 (comment) I will consider any patch that preserves the requests-kerberos shim while fixing the issue. |
I have now applied the following locally:
and started sending 200 tuples of The only realiable way I see is to associate the context with the connection and remove it immediately as soon as the context is complete. |
Yet another update: Reverted the update and used the autheticator on a per request basis. Works as designed. Now I need to patch WebDAV client because it does not access |
I have a similar usecase (downstream lib is sync and I call it in an async context with an executor) I made it work by prefixing the negotiate check i.e.
this:
Other than potentially actually needing to re-authenticate at some point is there a reason we can't do this? |
A better solution is to do per-request basis, as mentioned. Benefit: does not require changes in this lib. OR: client_lock = threading.Lock() and lock the sensitive spots. Works with the WebDAV module. |
Since there's a lot of code in common between this and requests/requests-kerberos, I believe requests-gssapi has some concurrency bugs as well.
requests/requests-kerberos#113 has details, and requests/requests-kerberos#114 has a fix which can be adapted.
The problem stems from how we index
gssapi.SecurityContext
objects byhostname
. If you have multiple threads sharing anHTTPSPNEGOAuth
object, and they both send requests to the same host:SecurityContext
to authenticate a request destined tofoo.com
and caches it inself.context["foo.com"]
and uses it tostep()
.SecurityContext
to authenticate another request, also destined tofoo.com
and caches it inself.context["foo.com"]
, overwriting theSecurityContext
placed there by thread1, and uses it tostep()
.SecurityContext
(generated by thread2) to authenticate the response fromfoo.com
, attempts tostep()
with the token it received, and ...At this point, we're likely to either get a mutual authentication exception because the
SecurityContext
was used for a different request, or it may happen to work due to implementation details (though probably not). And even if it did work, when thread2 receives its response and attempts to authenticate it, it's likely to get a mutual authentication exception because theSecurityContext
was fully established.And the potential is also there for there to be a concurrency issue within
generate_request_header
alone, since it always accesses theSecurityContext
via theself.context
dictionary. Depending on how frequently the interpreter re-schedules threads (and the GIL is released), it's possible for thread1 to generate its context, then have the interpreter schedule thread2 which will replace it with another context. Then whichever one callsstep()
on it first will succeed, and whichever one callsstep()
on it second will likely fail since they'll both use the same context since they're accessing it via theself.context
dictionary.The solution for this is to index by the request (or PreparedRequest) object, not the hostname in the url in the request as we currently do.
As the original author of the code in question, my bad.
The text was updated successfully, but these errors were encountered: