fixes bug 278885 "cache access denied from (ntlm) proxy on websites that require basic authentication" patch by jr@eenterphace.org, r+sr=darin, a=asa

This commit is contained in:
darin%meer.net 2005-05-15 17:30:56 +00:00
parent 91ba84e306
commit 25e23f221e
2 changed files with 124 additions and 11 deletions

View File

@ -103,6 +103,7 @@ nsHttpChannel::nsHttpChannel()
, mCacheAccess(0)
, mPostID(0)
, mRequestTime(0)
, mProxyAuthContinuationState(nsnull)
, mAuthContinuationState(nsnull)
, mStartPos(LL_MaxUint())
, mRedirectionLimit(gHttpHandler->RedirectionLimit())
@ -142,6 +143,7 @@ nsHttpChannel::~nsHttpChannel()
NS_IF_RELEASE(mConnectionInfo);
NS_IF_RELEASE(mTransaction);
NS_IF_RELEASE(mProxyAuthContinuationState);
NS_IF_RELEASE(mAuthContinuationState);
// release our reference to the handler
@ -720,6 +722,13 @@ nsHttpChannel::ProcessResponse()
CheckForSuperfluousAuth();
if (mCanceled)
return CallOnStartRequest();
if (mAuthContinuationState) {
// reset the current continuation state because our last
// authentication attempt has been completed successfully
NS_RELEASE(mAuthContinuationState);
LOG((" continuation state has been reset"));
}
}
// handle different server response categories. Note that we handle
@ -2079,6 +2088,18 @@ nsHttpChannel::GenCredsAndSetEntry(nsIHttpAuthenticator *auth,
if (NS_FAILED(rv)) return rv;
nsISupports *ss = sessionState;
// set informations that depend on whether
// we're authenticating against a proxy
// or a webserver
nsISupports **continuationState;
if (proxyAuth) {
continuationState = &mProxyAuthContinuationState;
} else {
continuationState = &mAuthContinuationState;
}
rv = auth->GenerateCredentials(this,
challenge,
proxyAuth,
@ -2086,8 +2107,9 @@ nsHttpChannel::GenCredsAndSetEntry(nsIHttpAuthenticator *auth,
ident.User(),
ident.Password(),
&ss,
&mAuthContinuationState,
&*continuationState,
result);
sessionState.swap(ss);
if (NS_FAILED(rv)) return rv;
@ -2128,6 +2150,10 @@ nsHttpChannel::ProcessAuthentication(PRUint32 httpStatus)
const char *challenges;
PRBool proxyAuth = (httpStatus == 407);
nsresult rv = PrepareForAuthentication(proxyAuth);
if (NS_FAILED(rv))
return rv;
if (proxyAuth) {
// only allow a proxy challenge if we have a proxy server configured.
// otherwise, we could inadvertantly expose the user's proxy
@ -2153,7 +2179,7 @@ nsHttpChannel::ProcessAuthentication(PRUint32 httpStatus)
NS_ENSURE_TRUE(challenges, NS_ERROR_UNEXPECTED);
nsCAutoString creds;
nsresult rv = GetCredentials(challenges, proxyAuth, creds);
rv = GetCredentials(challenges, proxyAuth, creds);
if (NS_FAILED(rv))
LOG(("unable to authenticate\n"));
else {
@ -2168,6 +2194,53 @@ nsHttpChannel::ProcessAuthentication(PRUint32 httpStatus)
return rv;
}
nsresult
nsHttpChannel::PrepareForAuthentication(PRBool proxyAuth)
{
LOG(("nsHttpChannel::PrepareForAuthentication [this=%x]\n", this));
if (!proxyAuth) {
// reset the current proxy continuation state because our last
// authentication attempt was completed successfully.
NS_IF_RELEASE(mProxyAuthContinuationState);
LOG((" proxy continuation state has been reset"));
}
if (!mConnectionInfo->UsingHttpProxy() || mProxyAuthType.IsEmpty())
return NS_OK;
// We need to remove any Proxy_Authorization header left over from a
// non-request based authentication handshake (e.g., for NTLM auth).
nsCAutoString contractId;
contractId.Assign(NS_HTTP_AUTHENTICATOR_CONTRACTID_PREFIX);
contractId.Append(mProxyAuthType);
nsresult rv;
nsCOMPtr<nsIHttpAuthenticator> precedingAuth =
do_GetService(contractId.get(), &rv);
if (NS_FAILED(rv))
return rv;
PRUint32 precedingAuthFlags;
rv = precedingAuth->GetAuthFlags(&precedingAuthFlags);
if (NS_FAILED(rv))
return rv;
if (!(precedingAuthFlags & nsIHttpAuthenticator::REQUEST_BASED)) {
const char *challenges =
mResponseHead->PeekHeader(nsHttp::Proxy_Authenticate);
if (!challenges) {
// delete the proxy authorization header because we weren't
// asked to authenticate
mRequestHead.ClearHeader(nsHttp::Proxy_Authorization);
LOG((" cleared proxy authorization header"));
}
}
return NS_OK;
}
nsresult
nsHttpChannel::GetCredentials(const char *challenges,
PRBool proxyAuth,
@ -2179,6 +2252,19 @@ nsHttpChannel::GetCredentials(const char *challenges,
nsCString authType; // force heap allocation to enable string sharing since
// we'll be assigning this value into mAuthType.
// set informations that depend on whether we're authenticating against a
// proxy or a webserver
nsISupports **currentContinuationState;
nsCString *currentAuthType;
if (proxyAuth) {
currentContinuationState = &mProxyAuthContinuationState;
currentAuthType = &mProxyAuthType;
} else {
currentContinuationState = &mAuthContinuationState;
currentAuthType = &mAuthType;
}
nsresult rv = NS_ERROR_NOT_AVAILABLE;
PRBool gotCreds = PR_FALSE;
@ -2200,7 +2286,7 @@ nsHttpChannel::GetCredentials(const char *challenges,
// we find a challenge corresponding to the previously tried auth
// type.
//
if (!mAuthType.IsEmpty() && authType != mAuthType)
if (!currentAuthType->IsEmpty() && authType != *currentAuthType)
continue;
//
@ -2221,22 +2307,26 @@ nsHttpChannel::GetCredentials(const char *challenges,
proxyAuth, auth, creds);
if (NS_SUCCEEDED(rv)) {
gotCreds = PR_TRUE;
mAuthType = authType;
*currentAuthType = authType;
break;
}
// reset the auth type and continuation state
mAuthType.Truncate();
NS_IF_RELEASE(mAuthContinuationState);
NS_IF_RELEASE(*currentContinuationState);
currentAuthType->Truncate();
}
}
if (!gotCreds && !mAuthType.IsEmpty()) {
if (!gotCreds && !currentAuthType->IsEmpty()) {
// looks like we never found the auth type we were looking for.
// reset the auth type and continuation state, and try again.
mAuthType.Truncate();
NS_IF_RELEASE(mAuthContinuationState);
currentAuthType->Truncate();
NS_IF_RELEASE(*currentContinuationState);
rv = GetCredentials(challenges, proxyAuth, creds);
}
return rv;
}
@ -2272,11 +2362,15 @@ nsHttpChannel::GetCredentialsForChallenge(const char *challenge,
}
*/
// set informations that depend on whether
// we're authenticating against a proxy
// or a webserver
const char *host;
PRInt32 port;
nsHttpAuthIdentity *ident;
nsCAutoString path, scheme;
PRBool identFromURI = PR_FALSE;
nsISupports **continuationState;
if (proxyAuth) {
NS_ASSERTION (mConnectionInfo->UsingHttpProxy(), "proxyAuth is true, but no HTTP proxy is configured!");
@ -2285,6 +2379,8 @@ nsHttpChannel::GetCredentialsForChallenge(const char *challenge,
port = mConnectionInfo->ProxyPort();
ident = &mProxyIdent;
scheme.AssignLiteral("http");
continuationState = &mProxyAuthContinuationState;
}
else {
host = mConnectionInfo->Host();
@ -2303,6 +2399,8 @@ nsHttpChannel::GetCredentialsForChallenge(const char *challenge,
GetIdentityFromURI(authFlags, mIdent);
identFromURI = !mIdent.IsEmpty();
}
continuationState = &mAuthContinuationState;
}
//
@ -2327,7 +2425,7 @@ nsHttpChannel::GetCredentialsForChallenge(const char *challenge,
challenge,
proxyAuth,
&sessionState,
&mAuthContinuationState,
&*continuationState,
&identityInvalid);
sessionStateGrip.swap(sessionState);
if (NS_FAILED(rv)) return rv;
@ -2705,6 +2803,17 @@ nsHttpChannel::SetAuthorizationHeader(nsHttpAuthCache *authCache,
nsHttpAuthEntry *entry = nsnull;
nsresult rv;
// set informations that depend on whether
// we're authenticating against a proxy
// or a webserver
nsISupports **continuationState;
if (header == nsHttp::Proxy_Authorization) {
continuationState = &mProxyAuthContinuationState;
} else {
continuationState = &mAuthContinuationState;
}
rv = authCache->GetAuthEntryForPath(scheme, host, port, path, &entry);
if (NS_SUCCEEDED(rv)) {
// if we are trying to add a header for origin server auth and if the
@ -2747,9 +2856,10 @@ nsHttpChannel::SetAuthorizationHeader(nsHttpAuthCache *authCache,
entry->mMetaData, getter_Copies(temp));
if (NS_SUCCEEDED(rv))
creds = temp.get();
// make sure the continuation state is null since we do not
// support mixing preemptive and 'multirequest' authentication.
NS_IF_RELEASE(mAuthContinuationState);
NS_IF_RELEASE(*continuationState);
}
}
if (creds[0]) {

View File

@ -181,6 +181,7 @@ private:
nsresult OnDoneReadingPartialCacheEntry(PRBool *streamDone);
// auth specific methods
nsresult PrepareForAuthentication(PRBool proxyAuth);
nsresult GenCredsAndSetEntry(nsIHttpAuthenticator *, PRBool proxyAuth, const char *scheme, const char *host, PRInt32 port, const char *dir, const char *realm, const char *challenge, const nsHttpAuthIdentity &ident, nsCOMPtr<nsISupports> &session, char **result);
nsresult GetCredentials(const char *challenges, PRBool proxyAuth, nsAFlatCString &creds);
nsresult GetCredentialsForChallenge(const char *challenge, const char *scheme, PRBool proxyAuth, nsIHttpAuthenticator *auth, nsAFlatCString &creds);
@ -243,6 +244,8 @@ private:
PRUint32 mRequestTime;
// auth specific data
nsISupports *mProxyAuthContinuationState;
nsCString mProxyAuthType;
nsISupports *mAuthContinuationState;
nsCString mAuthType;
nsHttpAuthIdentity mIdent;