Some malfunctioning HTTP servers may return a qop directive with no token, as
opposed to correctly omitting the qop directive completely. For example:
header: WWW-Authenticate: Digest realm="foobar_api_auth", qop="",
nonce="a12059eaaad0b86ece8f62f04cbafed6", algorithm="MD5",
stale="false"
Prior to this patch, requests would respond with a 'None' Authorization header.
While the server is certainly incorrect, this patch updates requests to be
more tolerant to this kind of shenaniganry. If we receive an empty string for
the value of the qop attribute, we instead treat that as if the qop attribute
was simply not provided.
Closes#2916
The existing code counts the number of 401 responses in the num_401_calls
authenticator attribute. This is in place so as to ensure the necessary auth
header is sent, while avoiding infinite 401 loops (issue #547).
This commit makes num_401_calls an instance of threading.local() (previously
an integer), using num_401_calls.value as the counter.
It ensures that concurrent authentication requests get each their own counter
and behave as expected (otherwise every other concurrent request would have
its authentication fail).
If a session runs long enough (without constant activity) then the server can
expire the nonce the session has negotiated. If that happens the session will
get a new 401 response which we were immediately returning to the user. A user
would then have to essentially reinitialize session.auth each time they get an
unexpected 401.
Also, there's no need for setattr calls when we can simply assign the
attribute on the instance.
When using Digest Authentication, the client resends the same request
after the server responds with the 401 "Unauthorized". However, when
doing streaming uploads, it gets stuck because the body data (a
file-like object) is already consumed at the initial request.
The patch fixes this by rewinding the file-like object before
resending the request.
In Digest Access Authentication there are two possible values (four if you
count the not-present and both cases) for authentication. We were narrowly
handling one of the four cases. Now we handle two.
Hooks sometimes have to send requests (e.g. when responding to a 401 during
authentication).
All keyword arguments should be passed along when hooks are dispatched so that
if a user wanted to use a timeout, stream, specify a cert location with the
verify flag, etc, their specification can be followed.
Related to Issue #910. Specifically, OAuth won't sign the request unless
it gets a body type that is urlencoded or multipart. This is overly
restrictive. The correct behaviour is to sign the message without
including the body as part of the signature.