Bug 1064378 - Don't rewrite custom Authorization header set on a channel by cached credential. r=jduell

This commit is contained in:
Honza Bambas 2016-01-21 09:33:00 -05:00
parent 4d69c3f3b0
commit 23a5a0c89c
5 changed files with 41 additions and 13 deletions

View File

@ -237,6 +237,7 @@ nsHttpChannel::nsHttpChannel()
, mTransactionReplaced(false)
, mAuthRetryPending(false)
, mProxyAuthPending(false)
, mCustomAuthHeader(false)
, mResuming(false)
, mInitedCacheEntry(false)
, mFallbackChannel(false)
@ -1586,9 +1587,17 @@ nsHttpChannel::ProcessResponse()
break;
case 401:
case 407:
rv = mAuthProvider->ProcessAuthentication(
httpStatus, mConnectionInfo->EndToEndSSL() &&
mTransaction->ProxyConnectFailed());
if (MOZ_UNLIKELY(mCustomAuthHeader) && httpStatus == 401) {
// When a custom auth header fails, we don't want to try
// any cached credentials, nor we want to ask the user.
// It's up to the consumer to re-try w/o setting a custom
// auth header if cached credentials should be attempted.
rv = NS_ERROR_FAILURE;
} else {
rv = mAuthProvider->ProcessAuthentication(
httpStatus,
mConnectionInfo->EndToEndSSL() && mTransaction->ProxyConnectFailed());
}
if (rv == NS_ERROR_IN_PROGRESS) {
// authentication prompt has been invoked and result
// is expected asynchronously
@ -1603,17 +1612,16 @@ nsHttpChannel::ProcessResponse()
LOG(("Suspending the transaction, asynchronously prompting for credentials"));
mTransactionPump->Suspend();
rv = NS_OK;
}
else if (NS_FAILED(rv)) {
} else if (NS_FAILED(rv)) {
LOG(("ProcessAuthentication failed [rv=%x]\n", rv));
if (mTransaction->ProxyConnectFailed())
return ProcessFailedProxyConnect(httpStatus);
if (!mAuthRetryPending)
mAuthProvider->CheckForSuperfluousAuth();
rv = ProcessNormal();
}
else
} else {
mAuthRetryPending = true; // see DoAuthRetry
}
break;
default:
rv = ProcessNormal();
@ -4973,6 +4981,10 @@ nsHttpChannel::AsyncOpen(nsIStreamListener *listener, nsISupports *context)
// timing.
mAsyncOpenTime = TimeStamp::Now();
// Remember we have Authorization header set here. We need to check on it
// just once and early, AsyncOpen is the best place.
mCustomAuthHeader = !!mRequestHead.PeekHeader(nsHttp::Authorization);
// the only time we would already know the proxy information at this
// point would be if we were proxying a non-http protocol like ftp
if (!mProxyInfo && NS_SUCCEEDED(ResolveProxy()))
@ -5108,7 +5120,8 @@ nsHttpChannel::BeginConnect()
}
// check to see if authorization headers should be included
mAuthProvider->AddAuthorizationHeaders();
// mCustomAuthHeader is set in AsyncOpen if we find Authorization header
mAuthProvider->AddAuthorizationHeaders(mCustomAuthHeader);
// notify "http-on-modify-request" observers
CallOnModifyRequestObservers();

View File

@ -476,6 +476,10 @@ private:
uint32_t mTransactionReplaced : 1;
uint32_t mAuthRetryPending : 1;
uint32_t mProxyAuthPending : 1;
// Set if before the first authentication attempt a custom authorization
// header has been set on the channel. This will make that custom header
// go to the server instead of any cached credentials.
uint32_t mCustomAuthHeader : 1;
uint32_t mResuming : 1;
uint32_t mInitedCacheEntry : 1;
// True if we are loading a fallback cache entry from the

View File

@ -178,7 +178,7 @@ nsHttpChannelAuthProvider::ProcessAuthentication(uint32_t httpStatus,
}
NS_IMETHODIMP
nsHttpChannelAuthProvider::AddAuthorizationHeaders()
nsHttpChannelAuthProvider::AddAuthorizationHeaders(bool aDontUseCachedWWWCreds)
{
LOG(("nsHttpChannelAuthProvider::AddAuthorizationHeaders? "
"[this=%p channel=%p]\n", this, mAuthChannel));
@ -202,17 +202,24 @@ nsHttpChannelAuthProvider::AddAuthorizationHeaders()
// check if proxy credentials should be sent
const char *proxyHost = ProxyHost();
if (proxyHost && UsingHttpProxy())
if (proxyHost && UsingHttpProxy()) {
SetAuthorizationHeader(authCache, nsHttp::Proxy_Authorization,
"http", proxyHost, ProxyPort(),
nullptr, // proxy has no path
mProxyIdent);
}
if (loadFlags & nsIRequest::LOAD_ANONYMOUS) {
LOG(("Skipping Authorization header for anonymous load\n"));
return NS_OK;
}
if (aDontUseCachedWWWCreds) {
LOG(("Authorization header already present:"
" skipping adding auth header from cache\n"));
return NS_OK;
}
// check if server credentials should be sent
nsAutoCString path, scheme;
if (NS_SUCCEEDED(GetCurrentPath(path)) &&

View File

@ -25,7 +25,7 @@ interface nsIHttpAuthenticableChannel;
* called.
*/
[scriptable, uuid(c68f3def-c7c8-4ee8-861c-eef49a48b702)]
[scriptable, uuid(788f331b-2e1f-436c-b405-4f88a31a105b)]
interface nsIHttpChannelAuthProvider : nsICancelable
{
/**
@ -58,8 +58,12 @@ interface nsIHttpChannelAuthProvider : nsICancelable
/**
* Add credentials from the http auth cache.
*
* @param dontUseCachedWWWCreds
* When true, the method will not add any Authorization headers from
* the auth cache.
*/
void addAuthorizationHeaders();
void addAuthorizationHeaders(in boolean dontUseCachedWWWCreds);
/**
* Check if an unnecessary(and maybe malicious) url authentication has been

View File

@ -1,5 +1,5 @@
[send-authentication-basic-setrequestheader-existing-session.htm]
type: testharness
[XMLHttpRequest: send() - "Basic" authenticated request using setRequestHeader() when there is an existing session]
expected: FAIL
expected: PASS