Bug 1309438 - Don't reuse sticky connection after authentication failure. r=jduell

This commit is contained in:
Honza Bambas 2016-11-25 03:33:00 -05:00
parent 906fc553b2
commit 4d5a7285da
5 changed files with 67 additions and 1 deletions

View File

@ -5512,6 +5512,42 @@ NS_IMETHODIMP nsHttpChannel::OnAuthCancelled(bool userCancel)
return NS_OK;
}
NS_IMETHODIMP nsHttpChannel::CloseStickyConnection()
{
LOG(("nsHttpChannel::CloseStickyConnection this=%p", this));
// Require we are between OnStartRequest and OnStopRequest, because
// what we do here takes effect in OnStopRequest (not reusing the
// connection for next authentication round).
if (!mIsPending) {
LOG((" channel not pending"));
NS_ERROR("CloseStickyConnection not called before OnStopRequest, won't have any effect");
return NS_ERROR_UNEXPECTED;
}
MOZ_ASSERT(mTransaction);
if (!mTransaction) {
return NS_ERROR_UNEXPECTED;
}
if (!(mCaps & NS_HTTP_STICKY_CONNECTION ||
mTransaction->Caps() & NS_HTTP_STICKY_CONNECTION)) {
LOG((" not sticky"));
return NS_OK;
}
RefPtr<nsAHttpConnection> conn = mTransaction->GetConnectionReference();
if (!conn) {
LOG((" no connection"));
return NS_OK;
}
// This turns the IsPersistent() indicator on the connection to false,
// and makes us throw it away in OnStopRequest.
conn->DontReuse();
return NS_OK;
}
//-----------------------------------------------------------------------------
// nsHttpChannel::nsISupports
//-----------------------------------------------------------------------------

View File

@ -110,6 +110,7 @@ public:
NS_IMETHOD SetWWWCredentials(const nsACString & aCredentials) override;
NS_IMETHOD OnAuthAvailable() override;
NS_IMETHOD OnAuthCancelled(bool userCancel) override;
NS_IMETHOD CloseStickyConnection() override;
// Functions we implement from nsIHttpAuthenticableChannel but are
// declared in HttpBaseChannel must be implemented in this class. We
// just call the HttpBaseChannel:: impls.

View File

@ -79,6 +79,7 @@ nsHttpChannelAuthProvider::nsHttpChannelAuthProvider()
, mTriedHostAuth(false)
, mSuppressDefensiveAuth(false)
, mCrossOrigin(false)
, mConnectionBased(false)
, mHttpHandler(gHttpHandler)
{
}
@ -792,6 +793,18 @@ nsHttpChannelAuthProvider::GetCredentialsForChallenge(const char *challenge,
LOG((" identity invalid = %d\n", identityInvalid));
if (mConnectionBased && identityInvalid) {
// If the flag is set and identity is invalid, it means we received the first
// challange for a new negotiation round after negotiating a connection based
// auth failed (invalid password).
// The mConnectionBased flag is set later for the newly received challenge,
// so here it reflects the previous 401/7 response schema.
mAuthChannel->CloseStickyConnection();
mConnectionBased = false;
}
mConnectionBased = !!(authFlags & nsIHttpAuthenticator::CONNECTION_BASED);
if (identityInvalid) {
if (entry) {
if (ident->Equals(entry->Identity())) {
@ -1305,6 +1318,14 @@ NS_IMETHODIMP nsHttpChannelAuthProvider::OnAuthCancelled(nsISupports *aContext,
if (!mAuthChannel)
return NS_OK;
// When user cancels or auth fails we want to close the connection for
// connection based schemes like NTLM. Some servers don't like re-negotiation
// on the same connection.
if (mConnectionBased) {
mAuthChannel->CloseStickyConnection();
mConnectionBased = false;
}
if (userCancel) {
if (!mRemainingChallenges.IsEmpty()) {
// there are still some challenges to process, do so

View File

@ -174,7 +174,8 @@ private:
// If a cross-origin sub-resource is being loaded, this flag will be set.
// In that case, the prompt text will be different to warn users.
uint32_t mCrossOrigin : 1;
uint32_t mCrossOrigin : 1;
uint32_t mConnectionBased : 1;
RefPtr<nsHttpHandler> mHttpHandler; // keep gHttpHandler alive

View File

@ -105,4 +105,11 @@ interface nsIHttpAuthenticableChannel : nsIProxiedChannel
* If the user was cancelled has cancelled the authentication prompt.
*/
void onAuthCancelled(in boolean userCancel);
/**
* Tells the channel to drop and close any sticky connection, since this
* connection oriented schema cannot be negotiated second time on
* the same connection.
*/
void closeStickyConnection();
};