Skip to content

Concurrency issue in generate_request_header #8

Open
@mkomitee

Description

@mkomitee

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 by hostname. If you have multiple threads sharing an HTTPSPNEGOAuth object, and they both send requests to the same host:

  1. thread1 generates a SecurityContext to authenticate a request destined to foo.com and caches it in self.context["foo.com"] and uses it to step().
  2. thread2 generates a SecurityContext to authenticate another request, also destined to foo.com and caches it in self.context["foo.com"], overwriting the SecurityContext placed there by thread1, and uses it to step().
  3. thread1 receives a response, retrieves the SecurityContext (generated by thread2) to authenticate the response from foo.com, attempts to step() 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 the SecurityContext 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 the SecurityContext via the self.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 calls step() on it first will succeed, and whichever one calls step() on it second will likely fail since they'll both use the same context since they're accessing it via the self.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.

Metadata

Metadata

Assignees

No one assigned

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions