зеркало из https://github.com/mozilla/gecko-dev.git
Fix for bug 32335. Fixes to make basic auth use the realm for authenticating. Thanks to darin@netscape.com r=gagan, sr=shaver.
This commit is contained in:
Родитель
b1350427ed
Коммит
bbeb713db3
|
@ -89,6 +89,8 @@ interface nsIHTTPChannel : nsIChannel
|
|||
|
||||
attribute PRBool authTriedWithPrehost;
|
||||
|
||||
attribute string authRealm;
|
||||
|
||||
/*
|
||||
We need a way to switch off gzip, etc. compression on the fly
|
||||
so that SaveAs would work as expected. Eventually this needs to
|
||||
|
|
|
@ -78,6 +78,11 @@ nsAuthEngine::GetAuthString(nsIURI* i_URI, char** o_AuthString)
|
|||
// mAuthList may have been cleared from logout
|
||||
if (!mAuthList) return NS_OK;
|
||||
|
||||
PRUint32 count=0;
|
||||
(void)mAuthList->Count(&count);
|
||||
if (count<=0)
|
||||
return NS_OK; // not found
|
||||
|
||||
nsXPIDLCString host;
|
||||
rv = i_URI->GetHost(getter_Copies(host));
|
||||
if (NS_FAILED(rv)) return rv;
|
||||
|
@ -98,10 +103,6 @@ nsAuthEngine::GetAuthString(nsIURI* i_URI, char** o_AuthString)
|
|||
char *lastSlash = PL_strrchr(dir, '/');
|
||||
if (lastSlash) lastSlash[1] = '\0';
|
||||
|
||||
PRUint32 count=0;
|
||||
(void)mAuthList->Count(&count);
|
||||
if (count<=0)
|
||||
return NS_OK; // not found
|
||||
for (PRInt32 i = count-1; i>=0; --i)
|
||||
{
|
||||
nsAuth* auth = (nsAuth*)mAuthList->ElementAt(i);
|
||||
|
@ -167,6 +168,7 @@ nsAuthEngine::GetAuthString(nsIURI* i_URI, char** o_AuthString)
|
|||
nsresult
|
||||
nsAuthEngine::SetAuth(nsIURI* i_URI,
|
||||
const char* i_AuthString,
|
||||
const char* i_Realm,
|
||||
PRBool bProxyAuth)
|
||||
{
|
||||
nsresult rv;
|
||||
|
@ -209,7 +211,7 @@ nsAuthEngine::SetAuth(nsIURI* i_URI,
|
|||
CRTFREEIF(unescaped_AuthString);
|
||||
return rv;
|
||||
}
|
||||
nsAuth* auth = new nsAuth(i_URI, unescaped_AuthString);
|
||||
nsAuth* auth = new nsAuth(i_URI, unescaped_AuthString, nsnull, nsnull, i_Realm);
|
||||
CRTFREEIF(unescaped_AuthString);
|
||||
if (!auth)
|
||||
return NS_ERROR_OUT_OF_MEMORY;
|
||||
|
@ -274,5 +276,52 @@ nsAuthEngine::SetProxyAuthString(const char* host,
|
|||
rv = mIOService->NewURI(spec.GetBuffer(), nsnull, getter_AddRefs(uri));
|
||||
if (NS_FAILED(rv)) return rv;
|
||||
|
||||
return SetAuth(uri, i_AuthString, PR_TRUE);
|
||||
return SetAuth(uri, i_AuthString, nsnull, PR_TRUE);
|
||||
}
|
||||
|
||||
nsresult
|
||||
nsAuthEngine::GetAuthStringForRealm(nsIURI* i_URI, const char* i_Realm, char** o_AuthString)
|
||||
{
|
||||
nsresult rv = NS_OK;
|
||||
if (!o_AuthString)
|
||||
return NS_ERROR_NULL_POINTER;
|
||||
if (!i_Realm)
|
||||
return NS_ERROR_NULL_POINTER;
|
||||
*o_AuthString = nsnull;
|
||||
// list may have been cleared by logout...
|
||||
if (!mAuthList)
|
||||
return NS_OK;
|
||||
|
||||
PRUint32 count = 0;
|
||||
mAuthList->Count(&count);
|
||||
if (count <= 0)
|
||||
return NS_OK; // not found
|
||||
|
||||
nsXPIDLCString host;
|
||||
rv = i_URI->GetHost(getter_Copies(host));
|
||||
if (NS_FAILED(rv)) return rv;
|
||||
|
||||
PRInt32 port;
|
||||
rv = i_URI->GetPort(&port);
|
||||
if (NS_FAILED(rv)) return rv;
|
||||
|
||||
for (PRInt32 i = count-1; i>=0; --i)
|
||||
{
|
||||
nsAuth* auth = (nsAuth*) mAuthList->ElementAt(i);
|
||||
|
||||
nsXPIDLCString authHost;
|
||||
PRInt32 authPort;
|
||||
|
||||
auth->uri->GetHost(getter_Copies(authHost));
|
||||
auth->uri->GetPort(&authPort);
|
||||
|
||||
if ((0 == nsCRT::strcasecmp(authHost, host)) &&
|
||||
(0 == nsCRT::strcasecmp(auth->realm, i_Realm)) &&
|
||||
(port == authPort))
|
||||
{
|
||||
*o_AuthString = nsCRT::strdup(auth->encodedString);
|
||||
return (!*o_AuthString) ? NS_ERROR_OUT_OF_MEMORY : NS_OK;
|
||||
}
|
||||
}
|
||||
return NS_OK; // not found
|
||||
}
|
||||
|
|
|
@ -63,6 +63,16 @@ public:
|
|||
PRInt32 port,
|
||||
const char* i_AuthString);
|
||||
|
||||
// Get an auth string for a particular host/port/realm
|
||||
NS_IMETHOD GetAuthStringForRealm(nsIURI* i_URI,
|
||||
const char* i_Realm,
|
||||
char** o_AuthString);
|
||||
|
||||
// Set an auth string for a particular host/port/realm
|
||||
NS_IMETHOD SetAuthStringForRealm(nsIURI* i_URI,
|
||||
const char* i_Realm,
|
||||
const char* i_AuthString);
|
||||
|
||||
/*
|
||||
Expire all existing auth list entries including proxy auths.
|
||||
*/
|
||||
|
@ -72,6 +82,7 @@ protected:
|
|||
|
||||
NS_IMETHOD SetAuth(nsIURI* i_URI,
|
||||
const char* i_AuthString,
|
||||
const char* i_Realm = nsnull,
|
||||
PRBool bProxyAuth = PR_FALSE);
|
||||
|
||||
nsCOMPtr<nsISupportsArray> mAuthList;
|
||||
|
@ -89,4 +100,10 @@ nsAuthEngine::SetAuthString(nsIURI* i_URI, const char* i_AuthString)
|
|||
return SetAuth(i_URI, i_AuthString);
|
||||
}
|
||||
|
||||
inline nsresult
|
||||
nsAuthEngine::SetAuthStringForRealm(nsIURI* i_URI, const char* i_Realm, const char* i_AuthString)
|
||||
{
|
||||
return SetAuth(i_URI, i_AuthString, i_Realm);
|
||||
}
|
||||
|
||||
#endif /* _nsAuthEngine_h_ */
|
||||
|
|
|
@ -93,6 +93,7 @@ nsHTTPChannel::nsHTTPChannel(nsIURI* i_URL, nsHTTPHandler* i_Handler):
|
|||
mFiredOpenOnStartRequest(PR_FALSE),
|
||||
mFiredOpenOnStopRequest (PR_FALSE),
|
||||
mAuthTriedWithPrehost(PR_FALSE),
|
||||
mAuthRealm(nsnull),
|
||||
mProxy(0),
|
||||
mProxyPort(-1),
|
||||
mProxyType(nsnull),
|
||||
|
@ -139,6 +140,7 @@ nsHTTPChannel::~nsHTTPChannel()
|
|||
mPrompter = null_nsCOMPtr();
|
||||
mResponseContext = null_nsCOMPtr();
|
||||
mLoadGroup = null_nsCOMPtr();
|
||||
CRTFREEIF(mAuthRealm);
|
||||
CRTFREEIF(mProxy);
|
||||
CRTFREEIF(mProxyType);
|
||||
}
|
||||
|
@ -847,6 +849,27 @@ nsHTTPChannel::GetAuthTriedWithPrehost(PRBool* oTried)
|
|||
return NS_ERROR_NULL_POINTER;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsHTTPChannel::SetAuthRealm(const char* aAuthRealm)
|
||||
{
|
||||
CRTFREEIF(mAuthRealm);
|
||||
if (aAuthRealm)
|
||||
mAuthRealm = nsCRT::strdup(aAuthRealm);
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsHTTPChannel::GetAuthRealm(char** aAuthRealm)
|
||||
{
|
||||
if (aAuthRealm)
|
||||
{
|
||||
*aAuthRealm = nsCRT::strdup(mAuthRealm);
|
||||
return (*aAuthRealm) ? NS_OK : NS_ERROR_OUT_OF_MEMORY;
|
||||
}
|
||||
else
|
||||
return NS_ERROR_NULL_POINTER;
|
||||
}
|
||||
|
||||
// nsIInterfaceRequestor method
|
||||
NS_IMETHODIMP
|
||||
nsHTTPChannel::GetInterface(const nsIID &anIID, void **aResult )
|
||||
|
@ -2029,7 +2052,7 @@ nsHTTPChannel::Authenticate(const char *iChallenge, PRBool iProxyAuth)
|
|||
if (NS_FAILED(rv)) return rv;
|
||||
|
||||
//flush out existing records of this URI in authengine-
|
||||
nsAuthEngine* pEngine;
|
||||
nsAuthEngine* pEngine = nsnull;
|
||||
if (NS_SUCCEEDED(mHandler->GetAuthEngine(&pEngine)))
|
||||
{
|
||||
rv = pEngine->SetAuthString(mURI, 0);
|
||||
|
@ -2067,6 +2090,7 @@ nsHTTPChannel::Authenticate(const char *iChallenge, PRBool iProxyAuth)
|
|||
nsXPIDLCString authString;
|
||||
nsCAutoString authLine;
|
||||
nsCOMPtr<nsIAuthenticator> auth;
|
||||
nsCAutoString authRealm;
|
||||
|
||||
// multiple www-auth headers case
|
||||
// go thru each to see if we support that.
|
||||
|
@ -2123,8 +2147,6 @@ nsHTTPChannel::Authenticate(const char *iChallenge, PRBool iProxyAuth)
|
|||
Throw a modal dialog box asking for
|
||||
username, password. Prefill (!?!)
|
||||
*/
|
||||
if (!mPrompter)
|
||||
return NS_ERROR_FAILURE;
|
||||
PRBool retval = PR_FALSE;
|
||||
|
||||
//TODO localize it!
|
||||
|
@ -2152,6 +2174,9 @@ nsHTTPChannel::Authenticate(const char *iChallenge, PRBool iProxyAuth)
|
|||
if (realm != end) {
|
||||
message.AppendWithConversion(realm, end - realm);
|
||||
foundRealm = PR_TRUE;
|
||||
|
||||
// Remember this realm; we will set it as an attribute of the new channel.
|
||||
authRealm.Assign(realm, end - realm);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -2159,44 +2184,74 @@ nsHTTPChannel::Authenticate(const char *iChallenge, PRBool iProxyAuth)
|
|||
if (!foundRealm)
|
||||
message.AppendWithConversion(authLine.GetBuffer());
|
||||
|
||||
// get the hostname
|
||||
nsXPIDLCString hostname;
|
||||
if (NS_SUCCEEDED(mURI->GetHost(getter_Copies(hostname))))
|
||||
// but, if we did find a realm and this is the first time trying to
|
||||
// authenticate this channel (indicated by mAuthRealm == NULL), then
|
||||
// lookup the realm in the auth engine and try to authenticate using
|
||||
// the response.
|
||||
else if (!mAuthRealm)
|
||||
{
|
||||
// TODO localize
|
||||
message.AppendWithConversion(" at ");
|
||||
message.AppendWithConversion(hostname);
|
||||
// Get the authentication string for the realm. If not found, then
|
||||
// authString will be NULL, and we will be forced to prompt.
|
||||
if (pEngine)
|
||||
pEngine->GetAuthStringForRealm(mURI, authRealm, getter_Copies(authString));
|
||||
|
||||
#ifdef DEBUG_darin
|
||||
fprintf(stderr, "\n>>>>> Authentication for Realm: [realm=%s, auth=%s]\n\n", (const char*) authRealm, (const char*) authString);
|
||||
#endif
|
||||
}
|
||||
|
||||
// Get url
|
||||
nsXPIDLCString urlCString;
|
||||
mURI->GetPrePath(getter_Copies(urlCString));
|
||||
|
||||
nsAutoString prePath; // XXX i18n
|
||||
CopyASCIItoUCS2(nsLiteralCString(
|
||||
NS_STATIC_CAST(const char*, urlCString)), prePath);
|
||||
rv = mPrompter->PromptUsernameAndPassword(nsnull,
|
||||
message.GetUnicode(),
|
||||
prePath.GetUnicode(),
|
||||
nsIPrompt::SAVE_PASSWORD_PERMANENTLY,
|
||||
getter_Copies(userBuf),
|
||||
getter_Copies(passwdBuf),
|
||||
&retval);
|
||||
if (NS_FAILED(rv) || !retval) // let it go on if we cancelled auth...
|
||||
// Skip prompting if we already have an authentication string.
|
||||
if (!authString || !*authString)
|
||||
{
|
||||
// Delay this check until we absolutely would need the prompter
|
||||
if (!mPrompter) {
|
||||
NS_WARNING("Failed to prompt for username/password: nsHTTPChannel::mPrompter == NULL");
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
|
||||
// get the hostname
|
||||
nsXPIDLCString hostname;
|
||||
if (NS_SUCCEEDED(mURI->GetHost(getter_Copies(hostname))))
|
||||
{
|
||||
// TODO localize
|
||||
message.AppendWithConversion(" at ");
|
||||
message.AppendWithConversion(hostname);
|
||||
}
|
||||
|
||||
// Get url
|
||||
nsXPIDLCString urlCString;
|
||||
mURI->GetPrePath(getter_Copies(urlCString));
|
||||
|
||||
nsAutoString prePath; // XXX i18n
|
||||
CopyASCIItoUCS2(nsLiteralCString(
|
||||
NS_STATIC_CAST(const char*, urlCString)), prePath);
|
||||
rv = mPrompter->PromptUsernameAndPassword(nsnull,
|
||||
message.GetUnicode(),
|
||||
prePath.GetUnicode(),
|
||||
nsIPrompt::SAVE_PASSWORD_PERMANENTLY,
|
||||
getter_Copies(userBuf),
|
||||
getter_Copies(passwdBuf),
|
||||
&retval);
|
||||
if (NS_FAILED(rv) || !retval) // let it go on if we cancelled auth...
|
||||
return rv;
|
||||
}
|
||||
}
|
||||
|
||||
// Skip authentication if we already have an authentication string.
|
||||
if (!authString || !*authString)
|
||||
{
|
||||
if (!userBuf && interactionType == nsIAuthenticator::INTERACTION_STANDARD) {
|
||||
/* can't proceed without at least a username, can we? */
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
|
||||
if (NS_FAILED(rv) ||
|
||||
NS_FAILED(rv = auth->Authenticate(mURI, "http", authLine.GetBuffer(),
|
||||
userBuf, passwdBuf, mPrompter,
|
||||
getter_Copies(authString))))
|
||||
return rv;
|
||||
}
|
||||
|
||||
if (!userBuf && interactionType == nsIAuthenticator::INTERACTION_STANDARD) {
|
||||
/* can't proceed without at least a username, can we? */
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
|
||||
if (NS_FAILED(rv) ||
|
||||
NS_FAILED(rv = auth->Authenticate(mURI, "http", authLine.GetBuffer(),
|
||||
userBuf, passwdBuf, mPrompter,
|
||||
getter_Copies(authString))))
|
||||
return rv;
|
||||
|
||||
#if defined(DEBUG_shaver) || defined(DEBUG_gagan)
|
||||
fprintf(stderr, "Auth string: %s\n", (const char *)authString);
|
||||
#endif
|
||||
|
@ -2230,6 +2285,10 @@ nsHTTPChannel::Authenticate(const char *iChallenge, PRBool iProxyAuth)
|
|||
// Let it know that we have already tried prehost stuff...
|
||||
httpChannel->SetAuthTriedWithPrehost(PR_TRUE);
|
||||
|
||||
// Let it know that we are trying to access a realm
|
||||
if (authRealm)
|
||||
httpChannel->SetAuthRealm(authRealm);
|
||||
|
||||
if (mResponseDataListener)
|
||||
{
|
||||
// Fire the new request...
|
||||
|
@ -2315,10 +2374,21 @@ nsHTTPChannel::ProcessStatusCode(void)
|
|||
{
|
||||
rv = GetRequestHeader(nsHTTPAtoms::Authorization,
|
||||
getter_Copies(authString));
|
||||
pEngine->SetAuthString(mURI, authString);
|
||||
#ifdef DEBUG_darin
|
||||
fprintf(stderr, "\n>>>>> Auth Accepted!! [realm=%s, auth=%s]\n\n", mAuthRealm, (const char*) authString);
|
||||
#endif
|
||||
if (mAuthRealm)
|
||||
pEngine->SetAuthStringForRealm(mURI, mAuthRealm, authString);
|
||||
else
|
||||
pEngine->SetAuthString(mURI, authString);
|
||||
}
|
||||
else // clear out entry from single signon and our cache.
|
||||
{
|
||||
#ifdef DEBUG_darin
|
||||
rv = GetRequestHeader(nsHTTPAtoms::Authorization,
|
||||
getter_Copies(authString));
|
||||
fprintf(stderr, "\n>>>>> Auth Rejected!! [realm=%s, auth=%s]\n\n", mAuthRealm, (const char*) authString);
|
||||
#endif
|
||||
pEngine->SetAuthString(mURI, 0);
|
||||
|
||||
NS_WITH_SERVICE(nsIWalletService, walletService,
|
||||
|
|
|
@ -181,6 +181,7 @@ protected:
|
|||
And so we need to throw a dialog box!
|
||||
*/
|
||||
PRBool mAuthTriedWithPrehost;
|
||||
char* mAuthRealm;
|
||||
|
||||
char* mProxy;
|
||||
PRInt32 mProxyPort;
|
||||
|
|
Загрузка…
Ссылка в новой задаче