зеркало из https://github.com/mozilla/gecko-dev.git
fixes bug 15860 "support http/1.1 digest authentication"
patch=jab@atdot.org,pach@cs.cmu.edu,darin@netscape.com r=dougt@netscape.com sr=rpotts@netscape.com
This commit is contained in:
Родитель
7d640e36ad
Коммит
43dc5ff391
|
@ -31,11 +31,29 @@ interface nsIHttpAuthenticator : nsISupports
|
|||
/**
|
||||
* Called to generate the authentication credentials for a particular
|
||||
* server/proxy challenge.
|
||||
*
|
||||
* @param channel - the http channel requesting credentials
|
||||
* @param challenge - the server specified auth challenge
|
||||
* @param username - the username from which to generate credentials
|
||||
* @param password - the password from which to generate credentials
|
||||
* @param extra - additional information stored in the auth cache
|
||||
*/
|
||||
string generateCredentials(in nsIHttpChannel channel,
|
||||
in string challenge,
|
||||
in wstring username,
|
||||
in wstring password);
|
||||
in wstring password,
|
||||
in nsISupports metadata);
|
||||
|
||||
/**
|
||||
* indicates if credentials returned from GenerateCredentials can be reused
|
||||
*/
|
||||
boolean areCredentialsReusable();
|
||||
|
||||
/**
|
||||
* allocate authenticator specific metadata implementation. implementations
|
||||
* that don't need to store extra data in the auth cache can simply return NULL.
|
||||
*/
|
||||
nsISupports allocateMetaData();
|
||||
};
|
||||
|
||||
%{C++
|
||||
|
|
|
@ -35,6 +35,7 @@ REQUIRES = xpcom \
|
|||
mimetype \
|
||||
intl \
|
||||
exthandler \
|
||||
caps \
|
||||
$(NULL)
|
||||
|
||||
CPPSRCS = \
|
||||
|
@ -49,6 +50,7 @@ CPPSRCS = \
|
|||
nsHttpChunkedDecoder.cpp \
|
||||
nsHttpAuthCache.cpp \
|
||||
nsHttpBasicAuth.cpp \
|
||||
nsHttpDigestAuth.cpp \
|
||||
$(NULL)
|
||||
|
||||
LOCAL_INCLUDES=-I$(srcdir)/../../../streamconv/converters
|
||||
|
|
|
@ -28,6 +28,7 @@ REQUIRES = xpcom \
|
|||
mimetype \
|
||||
intl \
|
||||
exthandler \
|
||||
caps \
|
||||
$(NULL)
|
||||
include <$(DEPTH)/config/config.mak>
|
||||
|
||||
|
@ -48,6 +49,7 @@ CPP_OBJS= \
|
|||
.\$(OBJDIR)\nsHttpChunkedDecoder.obj \
|
||||
.\$(OBJDIR)\nsHttpAuthCache.obj \
|
||||
.\$(OBJDIR)\nsHttpBasicAuth.obj \
|
||||
.\$(OBJDIR)\nsHttpDigestAuth.obj \
|
||||
$(NULL)
|
||||
|
||||
include <$(DEPTH)\config\rules.mak>
|
||||
|
|
|
@ -141,4 +141,7 @@ PRTimeToSeconds(PRTime t_usec)
|
|||
#undef CLAMP
|
||||
#define CLAMP(x, low, high) (((x) > (high)) ? (high) : (((x) < (low)) ? (low) : (x)))
|
||||
|
||||
// nsCRT::strdup likes to convert nsnull to ""
|
||||
#define strdup_if(s) (s ? nsCRT::strdup(s) : nsnull)
|
||||
|
||||
#endif // nsHttp_h__
|
||||
|
|
|
@ -25,7 +25,7 @@
|
|||
#include "nsHttp.h"
|
||||
#include "nsHttpAuthCache.h"
|
||||
#include "nsString.h"
|
||||
#include "plstr.h"
|
||||
#include "nsCRT.h"
|
||||
#include "prprf.h"
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
|
@ -60,50 +60,55 @@ nsHttpAuthCache::Init()
|
|||
}
|
||||
|
||||
nsresult
|
||||
nsHttpAuthCache::GetCredentialsForPath(const char *host,
|
||||
nsHttpAuthCache::GetAuthEntryForPath(const char *host,
|
||||
PRInt32 port,
|
||||
const char *path,
|
||||
nsACString &realm,
|
||||
nsACString &creds)
|
||||
nsHttpAuthEntry **entry)
|
||||
{
|
||||
LOG(("nsHttpAuthCache::GetCredentialsForPath [host=%s:%d path=%s]\n",
|
||||
LOG(("nsHttpAuthCache::GetAuthEntryForPath [host=%s:%d path=%s]\n",
|
||||
host, port, path));
|
||||
|
||||
nsCAutoString key;
|
||||
nsEntryList *list = LookupEntryList(host, port, key);
|
||||
if (!list)
|
||||
nsHttpAuthNode *node = LookupAuthNode(host, port, key);
|
||||
if (!node)
|
||||
return NS_ERROR_NOT_AVAILABLE;
|
||||
|
||||
return list->GetCredentialsForPath(path, realm, creds);
|
||||
return node->GetAuthEntryForPath(path, entry);
|
||||
}
|
||||
|
||||
nsresult
|
||||
nsHttpAuthCache::GetCredentialsForDomain(const char *host,
|
||||
nsHttpAuthCache::GetAuthEntryForDomain(const char *host,
|
||||
PRInt32 port,
|
||||
const char *realm,
|
||||
nsACString &creds)
|
||||
nsHttpAuthEntry **entry)
|
||||
|
||||
{
|
||||
LOG(("nsHttpAuthCache::GetCredentialsForDomain [host=%s:%d realm=%s]\n",
|
||||
LOG(("nsHttpAuthCache::GetAuthEntryForDomain [host=%s:%d realm=%s]\n",
|
||||
host, port, realm));
|
||||
|
||||
nsCAutoString key;
|
||||
nsEntryList *list = LookupEntryList(host, port, key);
|
||||
if (!list)
|
||||
nsHttpAuthNode *node = LookupAuthNode(host, port, key);
|
||||
if (!node)
|
||||
return NS_ERROR_NOT_AVAILABLE;
|
||||
|
||||
return list->GetCredentialsForRealm(realm, creds);
|
||||
return node->GetAuthEntryForRealm(realm, entry);
|
||||
}
|
||||
|
||||
nsresult
|
||||
nsHttpAuthCache::SetCredentials(const char *host,
|
||||
nsHttpAuthCache::SetAuthEntry(const char *host,
|
||||
PRInt32 port,
|
||||
const char *path,
|
||||
const char *realm,
|
||||
const char *creds)
|
||||
const char *creds,
|
||||
const PRUnichar *user,
|
||||
const PRUnichar *pass,
|
||||
const char *challenge,
|
||||
nsISupports *metadata)
|
||||
{
|
||||
nsresult rv;
|
||||
|
||||
LOG(("nsHttpAuthCache::SetCredentials\n"));
|
||||
LOG(("nsHttpAuthCache::SetAuthEntry [host=%s:%d realm=%s path=%s metadata=%x]\n",
|
||||
host, port, realm, path, metadata));
|
||||
|
||||
if (!mDB) {
|
||||
rv = Init();
|
||||
|
@ -111,28 +116,28 @@ nsHttpAuthCache::SetCredentials(const char *host,
|
|||
}
|
||||
|
||||
nsCAutoString key;
|
||||
nsEntryList *list = LookupEntryList(host, port, key);
|
||||
nsHttpAuthNode *node = LookupAuthNode(host, port, key);
|
||||
|
||||
if (!list) {
|
||||
// only create a new list if we have a real entry
|
||||
if (!creds)
|
||||
if (!node) {
|
||||
// only create a new node if we have a real entry
|
||||
if (!creds && !user && !pass && !challenge)
|
||||
return NS_OK;
|
||||
|
||||
// create a new entry list and set the given entry
|
||||
list = new nsEntryList();
|
||||
if (!list)
|
||||
// create a new entry node and set the given entry
|
||||
node = new nsHttpAuthNode();
|
||||
if (!node)
|
||||
return NS_ERROR_OUT_OF_MEMORY;
|
||||
rv = list->SetCredentials(path, realm, creds);
|
||||
rv = node->SetAuthEntry(path, realm, creds, user, pass, challenge, metadata);
|
||||
if (NS_FAILED(rv))
|
||||
delete list;
|
||||
delete node;
|
||||
else
|
||||
PL_HashTableAdd(mDB, PL_strdup(key.get()), list);
|
||||
PL_HashTableAdd(mDB, nsCRT::strdup(key.get()), node);
|
||||
return rv;
|
||||
}
|
||||
|
||||
rv = list->SetCredentials(path, realm, creds);
|
||||
if (NS_SUCCEEDED(rv) && (list->Count() == 0)) {
|
||||
// the list has no longer has any entries
|
||||
rv = node->SetAuthEntry(path, realm, creds, user, pass, challenge, metadata);
|
||||
if (NS_SUCCEEDED(rv) && (node->EntryCount() == 0)) {
|
||||
// the node has no longer has any entries
|
||||
PL_HashTableRemove(mDB, key.get());
|
||||
}
|
||||
|
||||
|
@ -155,8 +160,8 @@ nsHttpAuthCache::ClearAll()
|
|||
// nsHttpAuthCache <private>
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
nsHttpAuthCache::nsEntryList *
|
||||
nsHttpAuthCache::LookupEntryList(const char *host, PRInt32 port, nsAFlatCString &key)
|
||||
nsHttpAuthNode *
|
||||
nsHttpAuthCache::LookupAuthNode(const char *host, PRInt32 port, nsAFlatCString &key)
|
||||
{
|
||||
char buf[32];
|
||||
|
||||
|
@ -169,7 +174,7 @@ nsHttpAuthCache::LookupEntryList(const char *host, PRInt32 port, nsAFlatCString
|
|||
key.Append(':');
|
||||
key.Append(buf);
|
||||
|
||||
return (nsEntryList *) PL_HashTableLookup(mDB, key.get());
|
||||
return (nsHttpAuthNode *) PL_HashTableLookup(mDB, key.get());
|
||||
}
|
||||
|
||||
void *
|
||||
|
@ -201,8 +206,8 @@ nsHttpAuthCache::FreeEntry(void *self, PLHashEntry *he, PRUintn flag)
|
|||
}
|
||||
else if (flag == HT_FREE_ENTRY) {
|
||||
// three wonderful flavors of freeing memory ;-)
|
||||
delete (nsEntryList *) he->value;
|
||||
PL_strfree((char *) he->key);
|
||||
delete (nsHttpAuthNode *) he->value;
|
||||
nsCRT::free((char *) he->key);
|
||||
free(he);
|
||||
}
|
||||
}
|
||||
|
@ -216,69 +221,60 @@ PLHashAllocOps nsHttpAuthCache::gHashAllocOps =
|
|||
};
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// nsHttpAuthCache::nsEntry
|
||||
// nsHttpAuthEntry
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
nsHttpAuthCache::
|
||||
nsEntry::nsEntry(const char *path, const char *realm, const char *creds)
|
||||
: mPath(PL_strdup(path))
|
||||
, mRealm(PL_strdup(realm))
|
||||
, mCreds(PL_strdup(creds))
|
||||
nsHttpAuthEntry::nsHttpAuthEntry(const char *path, const char *realm,
|
||||
const char *creds, const PRUnichar *user,
|
||||
const PRUnichar *pass, const char *challenge,
|
||||
nsISupports *metadata)
|
||||
: mPath(strdup_if(path))
|
||||
, mRealm(strdup_if(realm))
|
||||
, mCreds(strdup_if(creds))
|
||||
, mUser(strdup_if(user))
|
||||
, mPass(strdup_if(pass))
|
||||
, mChallenge(strdup_if(challenge))
|
||||
, mMetaData(metadata)
|
||||
{
|
||||
LOG(("Creating nsHttpAuthCache::nsEntry @%x\n", this));
|
||||
}
|
||||
|
||||
nsHttpAuthCache::
|
||||
nsEntry::~nsEntry()
|
||||
nsHttpAuthEntry::~nsHttpAuthEntry()
|
||||
{
|
||||
LOG(("Destroying nsHttpAuthCache::nsEntry @%x\n", this));
|
||||
|
||||
PL_strfree(mPath);
|
||||
PL_strfree(mRealm);
|
||||
PL_strfree(mCreds);
|
||||
}
|
||||
|
||||
void nsHttpAuthCache::
|
||||
nsEntry::SetPath(const char *path)
|
||||
{
|
||||
PL_strfree(mPath);
|
||||
mPath = PL_strdup(path);
|
||||
}
|
||||
|
||||
void nsHttpAuthCache::
|
||||
nsEntry::SetCreds(const char *creds)
|
||||
{
|
||||
PL_strfree(mCreds);
|
||||
mCreds = PL_strdup(creds);
|
||||
CRTFREEIF(mPath);
|
||||
CRTFREEIF(mRealm);
|
||||
CRTFREEIF(mCreds);
|
||||
CRTFREEIF(mUser);
|
||||
CRTFREEIF(mPass);
|
||||
CRTFREEIF(mChallenge);
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// nsHttpAuthCache::nsEntryList
|
||||
// nsHttpAuthNode
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
nsHttpAuthCache::
|
||||
nsEntryList::nsEntryList()
|
||||
nsHttpAuthNode::nsHttpAuthNode()
|
||||
{
|
||||
LOG(("Creating nsHttpAuthCache::nsEntryList @%x\n", this));
|
||||
LOG(("Creating nsHttpAuthNode @%x\n", this));
|
||||
}
|
||||
|
||||
nsHttpAuthCache::
|
||||
nsEntryList::~nsEntryList()
|
||||
nsHttpAuthNode::~nsHttpAuthNode()
|
||||
{
|
||||
LOG(("Destroying nsHttpAuthCache::nsEntryList @%x\n", this));
|
||||
LOG(("Destroying nsHttpAuthNode @%x\n", this));
|
||||
|
||||
PRInt32 i;
|
||||
for (i=0; i<mList.Count(); ++i)
|
||||
delete (nsEntry *) mList[i];
|
||||
delete (nsHttpAuthEntry *) mList[i];
|
||||
mList.Clear();
|
||||
}
|
||||
|
||||
nsresult nsHttpAuthCache::
|
||||
nsEntryList::GetCredentialsForPath(const char *path,
|
||||
nsACString &realm,
|
||||
nsACString &creds)
|
||||
nsresult
|
||||
nsHttpAuthNode::GetAuthEntryForPath(const char *path,
|
||||
nsHttpAuthEntry **entry)
|
||||
{
|
||||
nsEntry *entry = nsnull;
|
||||
*entry = nsnull;
|
||||
|
||||
// it's permissible to specify a null path, in which case we just treat
|
||||
// this as an empty string.
|
||||
|
@ -290,72 +286,67 @@ nsEntryList::GetCredentialsForPath(const char *path,
|
|||
// directory of an existing entry.
|
||||
PRInt32 i;
|
||||
for (i=0; i<mList.Count(); ++i) {
|
||||
entry = (nsEntry *) mList[i];
|
||||
if (!PL_strncmp(path, entry->Path(), PL_strlen(entry->Path())))
|
||||
*entry = (nsHttpAuthEntry *) mList[i];
|
||||
if (!nsCRT::strncmp(path, (*entry)->Path(), strlen((*entry)->Path())))
|
||||
break;
|
||||
entry = nsnull;
|
||||
*entry = nsnull;
|
||||
}
|
||||
|
||||
if (!entry)
|
||||
return NS_ERROR_NOT_AVAILABLE;
|
||||
|
||||
realm.Assign(entry->Realm());
|
||||
creds.Assign(entry->Creds());
|
||||
return NS_OK;
|
||||
return *entry ? NS_OK : NS_ERROR_NOT_AVAILABLE;
|
||||
}
|
||||
|
||||
nsresult nsHttpAuthCache::
|
||||
nsEntryList::GetCredentialsForRealm(const char *realm,
|
||||
nsACString &creds)
|
||||
nsresult
|
||||
nsHttpAuthNode::GetAuthEntryForRealm(const char *realm,
|
||||
nsHttpAuthEntry **entry)
|
||||
{
|
||||
NS_ENSURE_ARG_POINTER(realm);
|
||||
|
||||
nsEntry *entry = nsnull;
|
||||
*entry = nsnull;
|
||||
|
||||
// look for an entry that matches this realm
|
||||
PRInt32 i;
|
||||
for (i=0; i<mList.Count(); ++i) {
|
||||
entry = (nsEntry *) mList[i];
|
||||
if (!PL_strcmp(realm, entry->Realm()))
|
||||
*entry = (nsHttpAuthEntry *) mList[i];
|
||||
if (!nsCRT::strcmp(realm, (*entry)->Realm()))
|
||||
break;
|
||||
entry = nsnull;
|
||||
*entry = nsnull;
|
||||
}
|
||||
|
||||
if (!entry)
|
||||
return NS_ERROR_NOT_AVAILABLE;
|
||||
|
||||
creds.Assign(entry->Creds());
|
||||
return NS_OK;
|
||||
return *entry ? NS_OK : NS_ERROR_NOT_AVAILABLE;
|
||||
}
|
||||
|
||||
nsresult nsHttpAuthCache::
|
||||
nsEntryList::SetCredentials(const char *path,
|
||||
nsresult
|
||||
nsHttpAuthNode::SetAuthEntry(const char *path,
|
||||
const char *realm,
|
||||
const char *creds)
|
||||
const char *creds,
|
||||
const PRUnichar *user,
|
||||
const PRUnichar *pass,
|
||||
const char *challenge,
|
||||
nsISupports *metadata)
|
||||
{
|
||||
NS_ENSURE_ARG_POINTER(realm);
|
||||
|
||||
nsEntry *entry = nsnull;
|
||||
nsHttpAuthEntry *entry = nsnull;
|
||||
|
||||
// look for an entry with a matching realm
|
||||
PRInt32 i;
|
||||
for (i=0; i<mList.Count(); ++i) {
|
||||
entry = (nsEntry *) mList[i];
|
||||
if (!PL_strcmp(realm, entry->Realm()))
|
||||
entry = (nsHttpAuthEntry *) mList[i];
|
||||
if (!nsCRT::strcmp(realm, entry->Realm()))
|
||||
break;
|
||||
entry = nsnull;
|
||||
}
|
||||
|
||||
if (!entry) {
|
||||
if (creds) {
|
||||
entry = new nsEntry(path, realm, creds);
|
||||
if (creds || user || pass || challenge) {
|
||||
entry = new nsHttpAuthEntry(path, realm, creds, user, pass, challenge, metadata);
|
||||
if (!entry)
|
||||
return NS_ERROR_OUT_OF_MEMORY;
|
||||
mList.AppendElement(entry);
|
||||
}
|
||||
// else, nothing to do
|
||||
}
|
||||
else if (!creds) {
|
||||
else if (!creds && !user && !pass && !challenge) {
|
||||
mList.RemoveElementAt(i);
|
||||
delete entry;
|
||||
}
|
||||
|
@ -363,12 +354,16 @@ nsEntryList::SetCredentials(const char *path,
|
|||
// update the entry...
|
||||
if (path) {
|
||||
// we should hold onto the top-most of the two path
|
||||
PRUint32 len1 = PL_strlen(path);
|
||||
PRUint32 len2 = PL_strlen(entry->Path());
|
||||
PRUint32 len1 = strlen(path);
|
||||
PRUint32 len2 = strlen(entry->Path());
|
||||
if (len1 < len2)
|
||||
entry->SetPath(path);
|
||||
}
|
||||
entry->SetCreds(creds);
|
||||
entry->SetUser(user);
|
||||
entry->SetPass(pass);
|
||||
entry->SetChallenge(challenge);
|
||||
entry->SetMetaData(metadata);
|
||||
}
|
||||
|
||||
return NS_OK;
|
||||
|
|
|
@ -40,13 +40,98 @@
|
|||
#ifndef nsHttpAuthCache_h__
|
||||
#define nsHttpAuthCache_h__
|
||||
|
||||
#include "nsHttp.h"
|
||||
#include "nsError.h"
|
||||
#include "nsVoidArray.h"
|
||||
#include "nsAString.h"
|
||||
#include "nsString.h"
|
||||
#include "nsCOMPtr.h"
|
||||
#include "plhash.h"
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// nsHttpAuthEntry
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
class nsHttpAuthEntry
|
||||
{
|
||||
public:
|
||||
const char *Path() { return mPath; }
|
||||
const char *Realm() { return mRealm; }
|
||||
const char *Creds() { return mCreds; }
|
||||
const PRUnichar *User() { return mUser; }
|
||||
const PRUnichar *Pass() { return mPass; }
|
||||
const char *Challenge() { return mChallenge; }
|
||||
nsISupports *MetaData() { return mMetaData; }
|
||||
|
||||
private:
|
||||
nsHttpAuthEntry(const char *path,
|
||||
const char *realm,
|
||||
const char *creds,
|
||||
const PRUnichar *user,
|
||||
const PRUnichar *pass,
|
||||
const char *challenge,
|
||||
nsISupports *metadata);
|
||||
~nsHttpAuthEntry();
|
||||
|
||||
void SetPath(const char *v) { CRTFREEIF(mPath); mPath = strdup_if(v); }
|
||||
void SetCreds(const char *v) { CRTFREEIF(mCreds); mCreds = strdup_if(v); }
|
||||
void SetUser(const PRUnichar *v) { CRTFREEIF(mUser); mUser = strdup_if(v); }
|
||||
void SetPass(const PRUnichar *v) { CRTFREEIF(mPass); mPass = strdup_if(v); }
|
||||
void SetChallenge(const char *v) { CRTFREEIF(mChallenge); mChallenge = strdup_if(v); }
|
||||
void SetMetaData(nsISupports *v) { mMetaData = v; }
|
||||
|
||||
private:
|
||||
char *mPath;
|
||||
char *mRealm;
|
||||
char *mCreds;
|
||||
PRUnichar *mUser;
|
||||
PRUnichar *mPass;
|
||||
char *mChallenge;
|
||||
nsCOMPtr<nsISupports> mMetaData;
|
||||
|
||||
friend class nsHttpAuthCache;
|
||||
friend class nsHttpAuthNode;
|
||||
};
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// nsHttpAuthNode
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
class nsHttpAuthNode
|
||||
{
|
||||
private:
|
||||
nsHttpAuthNode();
|
||||
~nsHttpAuthNode();
|
||||
|
||||
// path can be null, in which case we'll search for an entry
|
||||
// with a null path.
|
||||
nsresult GetAuthEntryForPath(const char *path,
|
||||
nsHttpAuthEntry **entry);
|
||||
|
||||
// realm must not be null
|
||||
nsresult GetAuthEntryForRealm(const char *realm,
|
||||
nsHttpAuthEntry **entry);
|
||||
|
||||
// if a matching entry is found, then credentials will be changed.
|
||||
nsresult SetAuthEntry(const char *path,
|
||||
const char *realm,
|
||||
const char *credentials,
|
||||
const PRUnichar *user,
|
||||
const PRUnichar *pass,
|
||||
const char *challenge,
|
||||
nsISupports *metadata);
|
||||
|
||||
PRUint32 EntryCount() { return (PRUint32) mList.Count(); }
|
||||
|
||||
private:
|
||||
nsVoidArray mList; // list of nsHttpAuthEntry objects
|
||||
|
||||
friend class nsHttpAuthCache;
|
||||
};
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// nsHttpAuthCache
|
||||
// (holds a hash table from host:port to nsHttpAuthNode)
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
class nsHttpAuthCache
|
||||
|
@ -57,86 +142,42 @@ public:
|
|||
|
||||
nsresult Init();
|
||||
|
||||
// host and port are required
|
||||
// path can be null
|
||||
nsresult GetCredentialsForPath(const char *host,
|
||||
// |host| and |port| are required
|
||||
// |path| can be null
|
||||
// |entry| is either null or a weak reference
|
||||
nsresult GetAuthEntryForPath(const char *host,
|
||||
PRInt32 port,
|
||||
const char *path,
|
||||
nsACString &realm,
|
||||
nsACString &credentials);
|
||||
nsHttpAuthEntry **entry);
|
||||
|
||||
// host and port are required
|
||||
// realm must not be null
|
||||
nsresult GetCredentialsForDomain(const char *host,
|
||||
// |host| and |port| are required
|
||||
// |realm| must not be null
|
||||
// |entry| is either null or a weak reference
|
||||
nsresult GetAuthEntryForDomain(const char *host,
|
||||
PRInt32 port,
|
||||
const char *realm,
|
||||
nsACString &credentials);
|
||||
nsHttpAuthEntry **entry);
|
||||
|
||||
// host and port are required
|
||||
// path can be null
|
||||
// realm must not be null
|
||||
// credentials, if null, clears the entry
|
||||
nsresult SetCredentials(const char *host,
|
||||
// |host| and |port| are required
|
||||
// |path| can be null
|
||||
// |realm| must not be null
|
||||
// if |credentials|, |user|, |pass|, and |challenge| are each
|
||||
// null, then the entry is deleted.
|
||||
nsresult SetAuthEntry(const char *host,
|
||||
PRInt32 port,
|
||||
const char *directory,
|
||||
const char *realm,
|
||||
const char *credentials);
|
||||
const char *credentials,
|
||||
const PRUnichar *user,
|
||||
const PRUnichar *pass,
|
||||
const char *challenge,
|
||||
nsISupports *metadata);
|
||||
|
||||
// Expire all existing auth list entries including proxy auths.
|
||||
// expire all existing auth list entries including proxy auths.
|
||||
nsresult ClearAll();
|
||||
|
||||
public: /* internal */
|
||||
|
||||
class nsEntry
|
||||
{
|
||||
public:
|
||||
nsEntry(const char *path,
|
||||
const char *realm,
|
||||
const char *creds);
|
||||
~nsEntry();
|
||||
|
||||
const char *Path() { return mPath; }
|
||||
const char *Realm() { return mRealm; }
|
||||
const char *Creds() { return mCreds; }
|
||||
|
||||
void SetPath(const char *);
|
||||
void SetCreds(const char *);
|
||||
|
||||
private:
|
||||
char *mPath;
|
||||
char *mRealm;
|
||||
char *mCreds;
|
||||
};
|
||||
|
||||
class nsEntryList
|
||||
{
|
||||
public:
|
||||
nsEntryList();
|
||||
~nsEntryList();
|
||||
|
||||
// path can be null, in which case we'll search for an entry
|
||||
// with a null path.
|
||||
nsresult GetCredentialsForPath(const char *path,
|
||||
nsACString &realm,
|
||||
nsACString &creds);
|
||||
|
||||
// realm must not be null
|
||||
nsresult GetCredentialsForRealm(const char *realm,
|
||||
nsACString &creds);
|
||||
|
||||
// if a matching entry is found, then credentials will be changed.
|
||||
nsresult SetCredentials(const char *path,
|
||||
const char *realm,
|
||||
const char *credentials);
|
||||
|
||||
PRUint32 Count() { return (PRUint32) mList.Count(); }
|
||||
|
||||
private:
|
||||
nsVoidArray mList;
|
||||
};
|
||||
|
||||
private:
|
||||
nsEntryList *LookupEntryList(const char *host, PRInt32 port, nsAFlatCString &key);
|
||||
nsHttpAuthNode *LookupAuthNode(const char *host, PRInt32 port, nsAFlatCString &key);
|
||||
|
||||
// hash table allocation functions
|
||||
static void* PR_CALLBACK AllocTable(void *, PRSize size);
|
||||
|
@ -147,7 +188,7 @@ private:
|
|||
static PLHashAllocOps gHashAllocOps;
|
||||
|
||||
private:
|
||||
PLHashTable *mDB; // "host:port" --> nsEntryList
|
||||
PLHashTable *mDB; // "host:port" --> nsHttpAuthNode
|
||||
};
|
||||
|
||||
#endif // nsHttpAuthCache_h__
|
||||
|
|
|
@ -70,22 +70,23 @@ NS_IMPL_ISUPPORTS1(nsHttpBasicAuth, nsIHttpAuthenticator);
|
|||
// nsHttpBasicAuth::nsIHttpAuthenticator
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
nsresult
|
||||
NS_IMETHODIMP
|
||||
nsHttpBasicAuth::GenerateCredentials(nsIHttpChannel *httpChannel,
|
||||
const char *challenge,
|
||||
const PRUnichar *username,
|
||||
const PRUnichar *password,
|
||||
nsISupports *extra,
|
||||
char **creds)
|
||||
|
||||
{
|
||||
LOG(("nsHttpBasicAuth::GenerateCredentials [challenge=%s]\n", challenge));
|
||||
|
||||
NS_ENSURE_ARG_POINTER(creds);
|
||||
|
||||
// we only know how to deal with Basic auth for http.
|
||||
PRBool isBasicAuth = !PL_strncasecmp(challenge, "basic", 5);
|
||||
NS_ENSURE_TRUE(isBasicAuth, NS_ERROR_UNEXPECTED);
|
||||
|
||||
NS_ENSURE_ARG_POINTER(creds);
|
||||
|
||||
// we work with ASCII around here
|
||||
nsCAutoString userpass;
|
||||
userpass.AssignWithConversion(username);
|
||||
|
@ -111,3 +112,17 @@ nsHttpBasicAuth::GenerateCredentials(nsIHttpChannel *httpChannel,
|
|||
PR_Free(b64userpass);
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsHttpBasicAuth::AreCredentialsReusable(PRBool *result)
|
||||
{
|
||||
*result = PR_TRUE;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsHttpBasicAuth::AllocateMetaData(nsISupports **result)
|
||||
{
|
||||
*result = nsnull;
|
||||
return NS_OK;
|
||||
}
|
||||
|
|
|
@ -64,7 +64,6 @@ nsHttpChannel::nsHttpChannel()
|
|||
, mRequestTime(0)
|
||||
, mIsPending(PR_FALSE)
|
||||
, mApplyConversion(PR_TRUE)
|
||||
, mTriedCredentialsFromPrehost(PR_FALSE)
|
||||
, mFromCacheOnly(PR_FALSE)
|
||||
, mCachedContentIsValid(PR_FALSE)
|
||||
, mResponseHeadersModified(PR_FALSE)
|
||||
|
@ -192,8 +191,7 @@ nsHttpChannel::Init(nsIURI *uri,
|
|||
if (NS_FAILED(rv)) return rv;
|
||||
|
||||
// check to see if authorization headers should be included
|
||||
rv = AddAuthorizationHeaders();
|
||||
if (NS_FAILED(rv)) return rv;
|
||||
AddAuthorizationHeaders();
|
||||
|
||||
// Notify nsIHttpNotify implementations
|
||||
rv = nsHttpHandler::get()->OnModifyRequest(this);
|
||||
|
@ -1313,7 +1311,6 @@ nsHttpChannel::GetCredentials(const char *challenges,
|
|||
PRBool proxyAuth,
|
||||
nsAFlatCString &creds)
|
||||
{
|
||||
nsAutoString user, pass;
|
||||
nsresult rv;
|
||||
|
||||
LOG(("nsHttpChannel::GetCredentials [this=%x proxyAuth=%d challenges=%s]\n",
|
||||
|
@ -1323,12 +1320,11 @@ nsHttpChannel::GetCredentials(const char *challenges,
|
|||
if (!authCache)
|
||||
return NS_ERROR_NOT_INITIALIZED;
|
||||
|
||||
// proxy auth's never in prehost
|
||||
if (!mTriedCredentialsFromPrehost && !proxyAuth) {
|
||||
rv = GetUserPassFromURI(user, pass);
|
||||
if (NS_FAILED(rv)) return rv;
|
||||
mTriedCredentialsFromPrehost = PR_TRUE;
|
||||
}
|
||||
// proxy auth's never in prehost. only take user:pass from URL if this
|
||||
// is the first 401 response (mUser and mPass hold previously attempted
|
||||
// username and password).
|
||||
if (!proxyAuth && mUser.IsEmpty() && mPass.IsEmpty())
|
||||
GetUserPassFromURI(getter_Copies(mUser), getter_Copies(mPass));
|
||||
|
||||
// figure out which challenge we can handle and which authenticator to use.
|
||||
nsCAutoString challenge;
|
||||
|
@ -1345,20 +1341,23 @@ nsHttpChannel::GetCredentials(const char *challenges,
|
|||
rv = ParseRealm(challenge.get(), realm);
|
||||
if (NS_FAILED(rv)) return rv;
|
||||
|
||||
const char *triedCreds = nsnull;
|
||||
const char *host;
|
||||
nsXPIDLCString path;
|
||||
nsXPIDLString *user;
|
||||
nsXPIDLString *pass;
|
||||
PRInt32 port;
|
||||
|
||||
if (proxyAuth) {
|
||||
host = mConnectionInfo->ProxyHost();
|
||||
port = mConnectionInfo->ProxyPort();
|
||||
triedCreds = mRequestHead.PeekHeader(nsHttp::Proxy_Authorization);
|
||||
user = &mProxyUser;
|
||||
pass = &mProxyPass;
|
||||
}
|
||||
else {
|
||||
host = mConnectionInfo->Host();
|
||||
port = mConnectionInfo->Port();
|
||||
triedCreds = mRequestHead.PeekHeader(nsHttp::Authorization);
|
||||
user = &mUser;
|
||||
pass = &mPass;
|
||||
|
||||
rv = GetCurrentPath(getter_Copies(path));
|
||||
if (NS_FAILED(rv)) return rv;
|
||||
|
@ -1370,42 +1369,72 @@ nsHttpChannel::GetCredentials(const char *challenges,
|
|||
// in the cache have changed, in which case we'd want to give them a
|
||||
// try instead.
|
||||
//
|
||||
authCache->GetCredentialsForDomain(host, port, realm.get(), creds);
|
||||
|
||||
if (triedCreds && !PL_strcmp(triedCreds, creds.get())) {
|
||||
// ok.. clear the credentials from the cache
|
||||
authCache->SetCredentials(host, port, nsnull, realm.get(), nsnull);
|
||||
creds.Truncate(0);
|
||||
nsHttpAuthEntry *entry = nsnull;
|
||||
authCache->GetAuthEntryForDomain(host, port, realm.get(), &entry);
|
||||
if (entry) {
|
||||
if (!nsCRT::strcmp(user->get(), entry->User()) &&
|
||||
!nsCRT::strcmp(pass->get(), entry->Pass())) {
|
||||
LOG(("clearing bad credentials from the auth cache\n"));
|
||||
// ok, we've already tried this user:pass combo, so clear the
|
||||
// corresponding entry from the auth cache.
|
||||
authCache->SetAuthEntry(host, port, nsnull, realm.get(),
|
||||
nsnull, nsnull, nsnull, nsnull, nsnull);
|
||||
entry = nsnull;
|
||||
user->Adopt(0);
|
||||
pass->Adopt(0);
|
||||
}
|
||||
// otherwise, let's try the credentials we got from the cache
|
||||
|
||||
if (!creds.IsEmpty()) {
|
||||
else {
|
||||
LOG(("taking user:pass from auth cache\n"));
|
||||
user->Adopt(nsCRT::strdup(entry->User()));
|
||||
pass->Adopt(nsCRT::strdup(entry->Pass()));
|
||||
if (entry->Creds()) {
|
||||
LOG(("using cached credentials!\n"));
|
||||
creds.Assign(entry->Creds());
|
||||
return NS_OK;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (user.IsEmpty()) {
|
||||
if (!entry && user->IsEmpty()) {
|
||||
// at this point we are forced to interact with the user to get their
|
||||
// username and password for this domain.
|
||||
rv = PromptForUserPass(host, port, proxyAuth, realm.get(), user, pass);
|
||||
rv = PromptForUserPass(host, port, proxyAuth, realm.get(),
|
||||
getter_Copies(*user),
|
||||
getter_Copies(*pass));
|
||||
if (NS_FAILED(rv)) return rv;
|
||||
}
|
||||
|
||||
// talk to the authenticator to get credentials for this user/pass combo.
|
||||
// ask the auth cache for a container for any meta data it might want to
|
||||
// store in the auth cache.
|
||||
nsCOMPtr<nsISupports> metadata;
|
||||
rv = auth->AllocateMetaData(getter_AddRefs(metadata));
|
||||
if (NS_FAILED(rv)) return rv;
|
||||
|
||||
// get credentials for the given user:pass
|
||||
nsXPIDLCString result;
|
||||
rv = auth->GenerateCredentials(this,
|
||||
challenge.get(),
|
||||
user.get(),
|
||||
pass.get(),
|
||||
rv = auth->GenerateCredentials(this, challenge.get(),
|
||||
user->get(), pass->get(), metadata,
|
||||
getter_Copies(result));
|
||||
if (NS_FAILED(rv)) return rv;
|
||||
|
||||
creds.Assign(result);
|
||||
// find out if this authenticator allows reuse of credentials
|
||||
PRBool reusable;
|
||||
rv = auth->AreCredentialsReusable(&reusable);
|
||||
if (NS_FAILED(rv)) return rv;
|
||||
|
||||
// store these credentials in the cache. we do this even though we don't
|
||||
// yet know that these credentials are valid b/c we need to avoid prompting
|
||||
// the user more than once in case the credentials are valid.
|
||||
return authCache->SetCredentials(host, port, path, realm.get(), creds.get());
|
||||
// let's try these credentials
|
||||
creds = result;
|
||||
|
||||
// create a cache entry. we do this even though we don't yet know that
|
||||
// these credentials are valid b/c we need to avoid prompting the user more
|
||||
// than once in case the credentials are valid.
|
||||
//
|
||||
// if the credentials are not reusable, then we don't bother sticking them
|
||||
// in the auth cache.
|
||||
return authCache->SetAuthEntry(host, port, path, realm.get(),
|
||||
reusable ? creds.get() : nsnull,
|
||||
user->get(), pass->get(),
|
||||
challenge.get(), metadata);
|
||||
}
|
||||
|
||||
nsresult
|
||||
|
@ -1460,35 +1489,24 @@ nsHttpChannel::GetAuthenticator(const char *scheme, nsIHttpAuthenticator **auth)
|
|||
return NS_OK;
|
||||
}
|
||||
|
||||
nsresult
|
||||
nsHttpChannel::GetUserPassFromURI(nsAString &user,
|
||||
nsAString &pass)
|
||||
void
|
||||
nsHttpChannel::GetUserPassFromURI(PRUnichar **user,
|
||||
PRUnichar **pass)
|
||||
{
|
||||
LOG(("nsHttpChannel::GetUserPassFromURI [this=%x]\n", this));
|
||||
|
||||
// XXX should be a necko utility function
|
||||
nsXPIDLCString prehost;
|
||||
mURI->GetPreHost(getter_Copies(prehost));
|
||||
if (prehost) {
|
||||
nsresult rv;
|
||||
|
||||
nsXPIDLCString buf;
|
||||
rv = nsStdUnescape((char*)prehost.get(), getter_Copies(buf));
|
||||
if (NS_FAILED(rv)) return rv;
|
||||
|
||||
char *p = PL_strchr(buf, ':');
|
||||
if (p) {
|
||||
// user:pass
|
||||
*p = 0;
|
||||
user = NS_ConvertASCIItoUCS2(buf);
|
||||
pass = NS_ConvertASCIItoUCS2(p+1);
|
||||
*user = nsnull;
|
||||
*pass = nsnull;
|
||||
|
||||
mURI->GetUsername(getter_Copies(buf));
|
||||
if (buf) {
|
||||
*user = ToNewUnicode(buf);
|
||||
mURI->GetPassword(getter_Copies(buf));
|
||||
if (buf)
|
||||
*pass = ToNewUnicode(buf);
|
||||
}
|
||||
else {
|
||||
// user
|
||||
user = NS_ConvertASCIItoUCS2(buf);
|
||||
}
|
||||
}
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
nsresult
|
||||
|
@ -1524,8 +1542,8 @@ nsHttpChannel::PromptForUserPass(const char *host,
|
|||
PRInt32 port,
|
||||
PRBool proxyAuth,
|
||||
const char *realm,
|
||||
nsAString &user,
|
||||
nsAString &pass)
|
||||
PRUnichar **user,
|
||||
PRUnichar **pass)
|
||||
{
|
||||
LOG(("nsHttpChannel::PromptForUserPass [this=%x realm=%s]\n", this, realm));
|
||||
|
||||
|
@ -1581,64 +1599,83 @@ nsHttpChannel::PromptForUserPass(const char *host,
|
|||
if (NS_FAILED(rv)) return rv;
|
||||
|
||||
// prompt the user...
|
||||
nsXPIDLString userBuf, passBuf;
|
||||
PRBool retval = PR_FALSE;
|
||||
rv = authPrompt->PromptUsernameAndPassword(nsnull,
|
||||
message.get(),
|
||||
rv = authPrompt->PromptUsernameAndPassword(nsnull, message.get(),
|
||||
NS_ConvertASCIItoUCS2(domain).get(),
|
||||
nsIAuthPrompt::SAVE_PASSWORD_PERMANENTLY,
|
||||
getter_Copies(userBuf),
|
||||
getter_Copies(passBuf),
|
||||
&retval);
|
||||
user, pass, &retval);
|
||||
if (NS_FAILED(rv))
|
||||
return rv;
|
||||
if (!retval)
|
||||
return NS_ERROR_ABORT;
|
||||
|
||||
user.Assign(userBuf);
|
||||
pass.Assign(passBuf);
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
nsresult
|
||||
nsHttpChannel::AddAuthorizationHeaders()
|
||||
void
|
||||
nsHttpChannel::SetAuthorizationHeader(nsHttpAuthCache *authCache,
|
||||
nsHttpAtom header,
|
||||
const char *host,
|
||||
PRInt32 port,
|
||||
const char *path,
|
||||
PRUnichar **user,
|
||||
PRUnichar **pass)
|
||||
{
|
||||
LOG(("nsHttpChannel::AddAuthorizationHeaders [this=%x]\n", this));
|
||||
nsHttpAuthCache *authCache = nsHttpHandler::get()->AuthCache();
|
||||
if (authCache) {
|
||||
nsCAutoString creds;
|
||||
nsCAutoString realm;
|
||||
nsCOMPtr<nsIHttpAuthenticator> auth;
|
||||
nsHttpAuthEntry *entry = nsnull;
|
||||
nsresult rv;
|
||||
|
||||
rv = authCache->GetAuthEntryForPath(host, port, path, &entry);
|
||||
if (NS_SUCCEEDED(rv)) {
|
||||
nsXPIDLCString temp;
|
||||
const char *creds = entry->Creds();
|
||||
if (!creds) {
|
||||
nsCAutoString foo;
|
||||
rv = SelectChallenge(entry->Challenge(), foo, getter_AddRefs(auth));
|
||||
if (NS_SUCCEEDED(rv)) {
|
||||
rv = auth->GenerateCredentials(this, entry->Challenge(),
|
||||
entry->User(), entry->Pass(),
|
||||
entry->MetaData(),
|
||||
getter_Copies(temp));
|
||||
if (NS_SUCCEEDED(rv)) {
|
||||
creds = temp.get();
|
||||
*user = nsCRT::strdup(entry->User());
|
||||
*pass = nsCRT::strdup(entry->Pass());
|
||||
}
|
||||
}
|
||||
}
|
||||
if (creds) {
|
||||
LOG((" adding \"%s\" request header\n", header.get()));
|
||||
mRequestHead.SetHeader(header, creds);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
nsHttpChannel::AddAuthorizationHeaders()
|
||||
{
|
||||
LOG(("nsHttpChannel::AddAuthorizationHeaders? [this=%x]\n", this));
|
||||
nsHttpAuthCache *authCache = nsHttpHandler::get()->AuthCache();
|
||||
if (authCache) {
|
||||
// check if proxy credentials should be sent
|
||||
const char *proxyHost = mConnectionInfo->ProxyHost();
|
||||
if (proxyHost) {
|
||||
rv = authCache->GetCredentialsForPath(proxyHost,
|
||||
mConnectionInfo->ProxyPort(),
|
||||
nsnull, realm, creds);
|
||||
if (NS_SUCCEEDED(rv)) {
|
||||
LOG(("adding Proxy-Authorization request header\n"));
|
||||
mRequestHead.SetHeader(nsHttp::Proxy_Authorization, creds.get());
|
||||
}
|
||||
}
|
||||
if (proxyHost)
|
||||
SetAuthorizationHeader(authCache, nsHttp::Proxy_Authorization,
|
||||
proxyHost, mConnectionInfo->ProxyPort(),
|
||||
nsnull,
|
||||
getter_Copies(mProxyUser),
|
||||
getter_Copies(mProxyPass));
|
||||
|
||||
// check if server credentials should be sent
|
||||
nsXPIDLCString path;
|
||||
rv = GetCurrentPath(getter_Copies(path));
|
||||
if (NS_FAILED(rv)) return rv;
|
||||
|
||||
rv = authCache->GetCredentialsForPath(mConnectionInfo->Host(),
|
||||
if (NS_SUCCEEDED(GetCurrentPath(getter_Copies(path))))
|
||||
SetAuthorizationHeader(authCache, nsHttp::Authorization,
|
||||
mConnectionInfo->Host(),
|
||||
mConnectionInfo->Port(),
|
||||
path.get(),
|
||||
realm,
|
||||
creds);
|
||||
if (NS_SUCCEEDED(rv)) {
|
||||
LOG(("adding Authorization request header\n"));
|
||||
mRequestHead.SetHeader(nsHttp::Authorization, creds.get());
|
||||
getter_Copies(mUser),
|
||||
getter_Copies(mPass));
|
||||
}
|
||||
}
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
nsresult
|
||||
nsHttpChannel::GetCurrentPath(char **path)
|
||||
|
|
|
@ -46,6 +46,7 @@
|
|||
|
||||
class nsHttpTransaction;
|
||||
class nsHttpResponseHead;
|
||||
class nsHttpAuthCache;
|
||||
class nsIHttpAuthenticator;
|
||||
class nsIProxyInfo;
|
||||
|
||||
|
@ -109,10 +110,11 @@ private:
|
|||
nsresult GetCredentials(const char *challenges, PRBool proxyAuth, nsAFlatCString &creds);
|
||||
nsresult SelectChallenge(const char *challenges, nsAFlatCString &challenge, nsIHttpAuthenticator **);
|
||||
nsresult GetAuthenticator(const char *scheme, nsIHttpAuthenticator **);
|
||||
nsresult GetUserPassFromURI(nsAString &user, nsAString &pass);
|
||||
void GetUserPassFromURI(PRUnichar **user, PRUnichar **pass);
|
||||
nsresult ParseRealm(const char *challenge, nsACString &realm);
|
||||
nsresult PromptForUserPass(const char *host, PRInt32 port, PRBool proxyAuth, const char *realm, nsAString &user, nsAString &pass);
|
||||
nsresult AddAuthorizationHeaders();
|
||||
nsresult PromptForUserPass(const char *host, PRInt32 port, PRBool proxyAuth, const char *realm, PRUnichar **user, PRUnichar **pass);
|
||||
void SetAuthorizationHeader(nsHttpAuthCache *, nsHttpAtom header, const char *host, PRInt32 port, const char *path, PRUnichar **user, PRUnichar **pass);
|
||||
void AddAuthorizationHeaders();
|
||||
nsresult GetCurrentPath(char **);
|
||||
|
||||
static void *PR_CALLBACK AsyncRedirect_EventHandlerFunc(PLEvent *);
|
||||
|
@ -155,9 +157,14 @@ private:
|
|||
PRUint32 mPostID;
|
||||
PRUint32 mRequestTime;
|
||||
|
||||
// auth specific data
|
||||
nsXPIDLString mUser;
|
||||
nsXPIDLString mPass;
|
||||
nsXPIDLString mProxyUser;
|
||||
nsXPIDLString mProxyPass;
|
||||
|
||||
PRPackedBool mIsPending;
|
||||
PRPackedBool mApplyConversion;
|
||||
PRPackedBool mTriedCredentialsFromPrehost;
|
||||
PRPackedBool mFromCacheOnly;
|
||||
PRPackedBool mCachedContentIsValid;
|
||||
PRPackedBool mResponseHeadersModified;
|
||||
|
|
|
@ -0,0 +1,556 @@
|
|||
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*-
|
||||
*
|
||||
* The contents of this file are subject to the Mozilla Public
|
||||
* License Version 1.1 (the "License"); you may not use this file
|
||||
* except in compliance with the License. You may obtain a copy of
|
||||
* the License at http://www.mozilla.org/MPL/
|
||||
*
|
||||
* Software distributed under the License is distributed on an "AS
|
||||
* IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
|
||||
* implied. See the License for the specific language governing
|
||||
* rights and limitations under the License.
|
||||
*
|
||||
* The Original Code is mozilla.org code.
|
||||
*
|
||||
* The Initial Developer of the Original Code is Netscape
|
||||
* Communications Corporation. Portions created by Netscape are
|
||||
* Copyright (C) 1998 Netscape Communications Corporation. All
|
||||
* Rights Reserved.
|
||||
*
|
||||
* Contributor(s):
|
||||
* Justin Bradford <jab@atdot.org> (original author of nsDigestAuth.cpp)
|
||||
* An-Cheng Huang <pach@cs.cmu.edu>
|
||||
* Darin Fisher <darin@netscape.com>
|
||||
*/
|
||||
|
||||
#include <stdlib.h>
|
||||
#include "nsHttp.h"
|
||||
#include "nsHttpDigestAuth.h"
|
||||
#include "nsIHttpChannel.h"
|
||||
#include "nsIServiceManager.h"
|
||||
#include "nsISupportsPrimitives.h"
|
||||
#include "nsIURI.h"
|
||||
#include "nsString.h"
|
||||
#include "nsReadableUtils.h"
|
||||
#include "plbase64.h"
|
||||
#include "plstr.h"
|
||||
#include "prprf.h"
|
||||
#include "prmem.h"
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// nsHttpDigestAuth <public>
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
nsHttpDigestAuth::nsHttpDigestAuth()
|
||||
{
|
||||
NS_INIT_ISUPPORTS();
|
||||
|
||||
mVerifier = do_GetService(SIGNATURE_VERIFIER_CONTRACTID);
|
||||
mGotVerifier = (mVerifier != nsnull);
|
||||
|
||||
#if defined(PR_LOGGING)
|
||||
if (mGotVerifier) {
|
||||
LOG(("nsHttpDigestAuth: Got signature_verifier\n"));
|
||||
} else {
|
||||
LOG(("nsHttpDigestAuth: No signature_verifier available\n"));
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// nsHttpDigestAuth::nsISupports
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
NS_IMPL_ISUPPORTS1(nsHttpDigestAuth, nsIHttpAuthenticator);
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// nsHttpDigestAuth <protected>
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
nsresult
|
||||
nsHttpDigestAuth::MD5Hash(const char *buf, PRUint32 len)
|
||||
{
|
||||
if (!mGotVerifier)
|
||||
return NS_ERROR_NOT_INITIALIZED;
|
||||
|
||||
nsresult rv;
|
||||
HASHContextStr *hid;
|
||||
unsigned char cbuf[DIGEST_LENGTH], *chash = cbuf;
|
||||
PRUint32 clen;
|
||||
|
||||
rv = mVerifier->HashBegin(nsISignatureVerifier::MD5, &hid);
|
||||
if (NS_FAILED(rv)) return rv;
|
||||
|
||||
rv = mVerifier->HashUpdate(hid, buf, len);
|
||||
if (NS_FAILED(rv)) return rv;
|
||||
|
||||
rv = mVerifier->HashEnd(hid, &chash, &clen, DIGEST_LENGTH);
|
||||
if (NS_FAILED(rv)) return rv;
|
||||
|
||||
nsCRT::memcpy(mHashBuf, chash, DIGEST_LENGTH);
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// nsHttpDigestAuth::nsIHttpAuthenticator
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsHttpDigestAuth::GenerateCredentials(nsIHttpChannel *httpChannel,
|
||||
const char *challenge,
|
||||
const PRUnichar *username,
|
||||
const PRUnichar *password,
|
||||
nsISupports *extra,
|
||||
char **creds)
|
||||
|
||||
{
|
||||
LOG(("nsHttpDigestAuth::GenerateCredentials [challenge=%s]\n", challenge));
|
||||
|
||||
NS_ENSURE_ARG_POINTER(creds);
|
||||
|
||||
PRBool isDigestAuth = !PL_strncasecmp(challenge, "digest ", 7);
|
||||
NS_ENSURE_TRUE(isDigestAuth, NS_ERROR_UNEXPECTED);
|
||||
|
||||
NS_ConvertUCS2toUTF8 cUser(username), cPass(password);
|
||||
|
||||
nsresult rv;
|
||||
nsCOMPtr<nsIURI> uri;
|
||||
nsXPIDLCString path;
|
||||
nsXPIDLCString httpMethod;
|
||||
|
||||
rv = httpChannel->GetURI(getter_AddRefs(uri));
|
||||
if (NS_FAILED(rv)) return rv;
|
||||
|
||||
rv = uri->GetPath(getter_Copies(path));
|
||||
if (NS_FAILED(rv)) return rv;
|
||||
|
||||
rv = httpChannel->GetRequestMethod(getter_Copies(httpMethod));
|
||||
if (NS_FAILED(rv)) return rv;
|
||||
|
||||
nsCAutoString realm, domain, nonce, opaque;
|
||||
PRBool stale;
|
||||
PRUint16 algorithm, qop;
|
||||
|
||||
rv = ParseChallenge(challenge, realm, domain, nonce, opaque,
|
||||
&stale, &algorithm, &qop);
|
||||
if (NS_FAILED(rv)) {
|
||||
LOG(("nsHttpDigestAuth::GenerateCredentials [ParseChallenge failed rv=%x]\n", rv));
|
||||
return rv;
|
||||
}
|
||||
|
||||
char ha1_digest[EXPANDED_DIGEST_LENGTH+1];
|
||||
char ha2_digest[EXPANDED_DIGEST_LENGTH+1];
|
||||
char response_digest[EXPANDED_DIGEST_LENGTH+1];
|
||||
char upload_data_digest[EXPANDED_DIGEST_LENGTH+1];
|
||||
|
||||
if (qop & QOP_AUTH_INT) {
|
||||
// we do not support auth-int "quality of protection" currently
|
||||
qop &= ~QOP_AUTH_INT;
|
||||
|
||||
NS_WARNING("no support for Digest authentication with data integrity quality of protection");
|
||||
|
||||
/* TODO: to support auth-int, we need to get an MD5 digest of
|
||||
* TODO: the data uploaded with this request.
|
||||
* TODO: however, i am not sure how to read in the file in without
|
||||
* TODO: disturbing the channel''s use of it. do i need to copy it
|
||||
* TODO: somehow?
|
||||
*/
|
||||
#if 0
|
||||
if (http_channel != nsnull)
|
||||
{
|
||||
nsIInputStream * upload;
|
||||
http_channel->GetUploadStream(&upload);
|
||||
if (upload) {
|
||||
char * upload_buffer;
|
||||
int upload_buffer_length = 0;
|
||||
//TODO: read input stream into buffer
|
||||
const char * digest = (const char*)
|
||||
nsNetwerkMD5Digest(upload_buffer, upload_buffer_length);
|
||||
ExpandToHex(digest, upload_data_digest);
|
||||
NS_RELEASE(upload);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
if (!(algorithm & ALGO_MD5 || algorithm & ALGO_MD5_SESS)) {
|
||||
// they asked only for algorithms that we do not support
|
||||
NS_WARNING("unsupported algorithm requested by Digest authentication");
|
||||
return NS_ERROR_NOT_IMPLEMENTED;
|
||||
}
|
||||
|
||||
//
|
||||
// the following are for increasing security. see RFC 2617 for more
|
||||
// information.
|
||||
//
|
||||
// nonce_count allows the server to keep track of auth challenges (to help
|
||||
// prevent spoofing). we increase this count every time.
|
||||
//
|
||||
char nonce_count[NONCE_COUNT_LENGTH+1] = "00000001"; // in hex
|
||||
nsCOMPtr<nsISupportsPRUint32> v(do_QueryInterface(extra));
|
||||
if (v) {
|
||||
PRUint32 nc;
|
||||
v->GetData(&nc);
|
||||
PR_snprintf(nonce_count, sizeof(nonce_count), "%08x", ++nc);
|
||||
v->SetData(nc);
|
||||
}
|
||||
LOG((" nonce_count=%s\n", nonce_count));
|
||||
|
||||
//
|
||||
// this lets the client verify the server response (via a server
|
||||
// returned Authentication-Info header). also used for session info.
|
||||
//
|
||||
nsCAutoString cnonce;
|
||||
static const char hexChar[] = "0123456789abcdef";
|
||||
for (int i=0; i<16; ++i) {
|
||||
cnonce.Append(hexChar[(int)(15.0 * rand()/(RAND_MAX + 1.0))]);
|
||||
}
|
||||
LOG((" cnonce=%s\n", cnonce.get()));
|
||||
|
||||
//
|
||||
// calculate credentials
|
||||
//
|
||||
|
||||
rv = CalculateHA1(cUser, cPass, realm, algorithm, nonce, cnonce, ha1_digest);
|
||||
if (NS_FAILED(rv)) return rv;
|
||||
|
||||
rv = CalculateHA2(httpMethod, path, qop, upload_data_digest, ha2_digest);
|
||||
if (NS_FAILED(rv)) return rv;
|
||||
|
||||
rv = CalculateResponse(ha1_digest, ha2_digest, nonce, qop, nonce_count,
|
||||
cnonce, response_digest);
|
||||
if (NS_FAILED(rv)) return rv;
|
||||
|
||||
nsCAutoString authString("Digest ");
|
||||
authString += "username=\"";
|
||||
authString += cUser;
|
||||
authString += NS_LITERAL_CSTRING("\", realm=\"");
|
||||
authString += realm;
|
||||
authString += NS_LITERAL_CSTRING("\", nonce=\"");
|
||||
authString += nonce;
|
||||
authString += NS_LITERAL_CSTRING("\", uri=\"");
|
||||
authString += path;
|
||||
if (algorithm & ALGO_SPECIFIED) {
|
||||
authString += "\", algorithm=";
|
||||
if (algorithm & ALGO_MD5_SESS)
|
||||
authString += "MD5-sess";
|
||||
else
|
||||
authString += "MD5";
|
||||
} else {
|
||||
authString += "\"";
|
||||
}
|
||||
authString += ", response=\"";
|
||||
authString += response_digest;
|
||||
|
||||
if (!opaque.IsEmpty()) {
|
||||
authString += "\", opaque=\"";
|
||||
authString += opaque;
|
||||
}
|
||||
|
||||
if (qop) {
|
||||
authString += "\", qop=";
|
||||
if (qop & QOP_AUTH_INT)
|
||||
authString += "auth-int";
|
||||
else
|
||||
authString += "auth";
|
||||
authString += ", nc=";
|
||||
authString += nonce_count;
|
||||
authString += ", cnonce=\"";
|
||||
authString += cnonce;
|
||||
}
|
||||
authString += "\"";
|
||||
|
||||
*creds = ToNewCString(authString);
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsHttpDigestAuth::AreCredentialsReusable(PRBool *result)
|
||||
{
|
||||
*result = PR_FALSE;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsHttpDigestAuth::AllocateMetaData(nsISupports **result)
|
||||
{
|
||||
nsresult rv;
|
||||
nsCOMPtr<nsISupportsPRUint32> v(
|
||||
do_CreateInstance(NS_SUPPORTS_PRUINT32_CONTRACTID, &rv));
|
||||
NS_ADDREF(*result = v);
|
||||
return rv;
|
||||
}
|
||||
|
||||
nsresult
|
||||
nsHttpDigestAuth::CalculateResponse(const char * ha1_digest,
|
||||
const char * ha2_digest,
|
||||
const nsAFlatCString & nonce,
|
||||
PRUint16 qop,
|
||||
const char * nonce_count,
|
||||
const nsAFlatCString & cnonce,
|
||||
char * result)
|
||||
{
|
||||
PRUint32 len = 2*EXPANDED_DIGEST_LENGTH + nonce.Length() + 2;
|
||||
|
||||
if (qop & QOP_AUTH || qop & QOP_AUTH_INT) {
|
||||
len += cnonce.Length() + NONCE_COUNT_LENGTH + 3;
|
||||
if (qop & QOP_AUTH_INT)
|
||||
len += 8; // length of "auth-int"
|
||||
else
|
||||
len += 4; // length of "auth"
|
||||
}
|
||||
|
||||
nsCAutoString contents;
|
||||
contents.SetCapacity(len);
|
||||
|
||||
contents.Assign(ha1_digest, EXPANDED_DIGEST_LENGTH);
|
||||
contents.Append(':');
|
||||
contents.Append(nonce);
|
||||
contents.Append(':');
|
||||
|
||||
if (qop & QOP_AUTH || qop & QOP_AUTH_INT) {
|
||||
contents.Append(nonce_count, NONCE_COUNT_LENGTH);
|
||||
contents.Append(':');
|
||||
contents.Append(cnonce);
|
||||
contents.Append(':');
|
||||
if (qop & QOP_AUTH_INT)
|
||||
contents.Append(NS_LITERAL_CSTRING("auth-int:"));
|
||||
else
|
||||
contents.Append(NS_LITERAL_CSTRING("auth:"));
|
||||
}
|
||||
|
||||
contents.Append(ha2_digest, EXPANDED_DIGEST_LENGTH);
|
||||
|
||||
nsresult rv = MD5Hash(contents.get(), contents.Length());
|
||||
if (NS_FAILED(rv)) return rv;
|
||||
|
||||
return ExpandToHex(mHashBuf, result);
|
||||
}
|
||||
|
||||
nsresult
|
||||
nsHttpDigestAuth::ExpandToHex(const char * digest, char * result)
|
||||
{
|
||||
PRInt16 index, value;
|
||||
|
||||
for (index = 0; index < DIGEST_LENGTH; index++) {
|
||||
value = (digest[index] >> 4) & 0xf;
|
||||
if (value < 10)
|
||||
result[index*2] = value + '0';
|
||||
else
|
||||
result[index*2] = value - 10 + 'a';
|
||||
|
||||
value = digest[index] & 0xf;
|
||||
if (value < 10)
|
||||
result[(index*2)+1] = value + '0';
|
||||
else
|
||||
result[(index*2)+1] = value - 10 + 'a';
|
||||
}
|
||||
|
||||
result[EXPANDED_DIGEST_LENGTH] = 0;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
nsresult
|
||||
nsHttpDigestAuth::CalculateHA1(const nsAFlatCString & username,
|
||||
const nsAFlatCString & password,
|
||||
const nsAFlatCString & realm,
|
||||
PRUint16 algorithm,
|
||||
const nsAFlatCString & nonce,
|
||||
const nsAFlatCString & cnonce,
|
||||
char * result)
|
||||
{
|
||||
PRInt16 len = username.Length() + password.Length() + realm.Length() + 2;
|
||||
if (algorithm & ALGO_MD5_SESS) {
|
||||
PRInt16 exlen = EXPANDED_DIGEST_LENGTH + nonce.Length() + cnonce.Length() + 2;
|
||||
if (exlen > len)
|
||||
len = exlen;
|
||||
}
|
||||
|
||||
nsCAutoString contents;
|
||||
contents.SetCapacity(len + 1);
|
||||
|
||||
contents.Assign(username);
|
||||
contents.Append(':');
|
||||
contents.Append(realm);
|
||||
contents.Append(':');
|
||||
contents.Append(password);
|
||||
|
||||
nsresult rv;
|
||||
rv = MD5Hash(contents.get(), contents.Length());
|
||||
if (NS_FAILED(rv))
|
||||
return rv;
|
||||
|
||||
if (algorithm & ALGO_MD5_SESS) {
|
||||
char part1[EXPANDED_DIGEST_LENGTH+1];
|
||||
ExpandToHex(mHashBuf, part1);
|
||||
|
||||
contents.Assign(part1, EXPANDED_DIGEST_LENGTH);
|
||||
contents.Append(':');
|
||||
contents.Append(nonce);
|
||||
contents.Append(':');
|
||||
contents.Append(cnonce);
|
||||
|
||||
rv = MD5Hash(contents.get(), contents.Length());
|
||||
if (NS_FAILED(rv))
|
||||
return rv;
|
||||
}
|
||||
|
||||
return ExpandToHex(mHashBuf, result);
|
||||
}
|
||||
|
||||
nsresult
|
||||
nsHttpDigestAuth::CalculateHA2(const nsAFlatCString & method,
|
||||
const nsAFlatCString & path,
|
||||
PRUint16 qop,
|
||||
const char * bodyDigest,
|
||||
char * result)
|
||||
{
|
||||
PRInt16 methodLen = method.Length();
|
||||
PRInt16 pathLen = path.Length();
|
||||
PRInt16 len = methodLen + pathLen + 1;
|
||||
|
||||
if (qop & QOP_AUTH_INT) {
|
||||
len += EXPANDED_DIGEST_LENGTH + 1;
|
||||
}
|
||||
|
||||
nsCAutoString contents;
|
||||
contents.SetCapacity(len);
|
||||
|
||||
contents.Assign(method);
|
||||
contents.Append(':');
|
||||
contents.Append(path);
|
||||
|
||||
if (qop & QOP_AUTH_INT) {
|
||||
contents.Append(':');
|
||||
contents.Append(bodyDigest, EXPANDED_DIGEST_LENGTH);
|
||||
}
|
||||
|
||||
nsresult rv = MD5Hash(contents.get(), contents.Length());
|
||||
if (NS_FAILED(rv)) return rv;
|
||||
|
||||
return ExpandToHex(mHashBuf, result);
|
||||
}
|
||||
|
||||
nsresult
|
||||
nsHttpDigestAuth::ParseChallenge(const char * challenge,
|
||||
nsACString & realm,
|
||||
nsACString & domain,
|
||||
nsACString & nonce,
|
||||
nsACString & opaque,
|
||||
PRBool * stale,
|
||||
PRUint16 * algorithm,
|
||||
PRUint16 * qop)
|
||||
{
|
||||
const char *p = challenge + 7; // first 7 characters are "Digest "
|
||||
|
||||
*stale = PR_FALSE;
|
||||
*algorithm = ALGO_MD5; // default is MD5
|
||||
*qop = 0;
|
||||
|
||||
for (;;) {
|
||||
while (*p && (*p == ',' || nsCRT::IsAsciiSpace(*p)))
|
||||
++p;
|
||||
if (!*p)
|
||||
break;
|
||||
|
||||
// name
|
||||
PRInt16 nameStart = (p - challenge);
|
||||
while (*p && !nsCRT::IsAsciiSpace(*p) && *p != '=')
|
||||
++p;
|
||||
if (!*p)
|
||||
return NS_ERROR_INVALID_ARG;
|
||||
PRInt16 nameLength = (p - challenge) - nameStart;
|
||||
|
||||
while (*p && (nsCRT::IsAsciiSpace(*p) || *p == '='))
|
||||
++p;
|
||||
if (!*p)
|
||||
return NS_ERROR_INVALID_ARG;
|
||||
|
||||
PRBool quoted = PR_FALSE;
|
||||
if (*p == '"') {
|
||||
++p;
|
||||
quoted = PR_TRUE;
|
||||
}
|
||||
|
||||
// value
|
||||
PRInt16 valueStart = (p - challenge);
|
||||
PRInt16 valueLength = 0;
|
||||
if (quoted) {
|
||||
while (*p && *p != '"')
|
||||
++p;
|
||||
if (*p != '"')
|
||||
return NS_ERROR_INVALID_ARG;
|
||||
valueLength = (p - challenge) - valueStart;
|
||||
++p;
|
||||
} else {
|
||||
while (*p && !nsCRT::IsAsciiSpace(*p) && *p != ',')
|
||||
++p;
|
||||
valueLength = (p - challenge) - valueStart;
|
||||
}
|
||||
|
||||
// extract information
|
||||
if (nameLength == 5 &&
|
||||
nsCRT::strncasecmp(challenge+nameStart, "realm", 5) == 0)
|
||||
{
|
||||
realm.Assign(challenge+valueStart, valueLength);
|
||||
}
|
||||
else if (nameLength == 6 &&
|
||||
nsCRT::strncasecmp(challenge+nameStart, "domain", 6) == 0)
|
||||
{
|
||||
domain.Assign(challenge+valueStart, valueLength);
|
||||
}
|
||||
else if (nameLength == 5 &&
|
||||
nsCRT::strncasecmp(challenge+nameStart, "nonce", 5) == 0)
|
||||
{
|
||||
nonce.Assign(challenge+valueStart, valueLength);
|
||||
}
|
||||
else if (nameLength == 6 &&
|
||||
nsCRT::strncasecmp(challenge+nameStart, "opaque", 6) == 0)
|
||||
{
|
||||
opaque.Assign(challenge+valueStart, valueLength);
|
||||
}
|
||||
else if (nameLength == 5 &&
|
||||
nsCRT::strncasecmp(challenge+nameStart, "stale", 5) == 0)
|
||||
{
|
||||
if (nsCRT::strncasecmp(challenge+valueStart, "true", 4) == 0)
|
||||
*stale = PR_TRUE;
|
||||
else
|
||||
*stale = PR_FALSE;
|
||||
}
|
||||
else if (nameLength == 9 &&
|
||||
nsCRT::strncasecmp(challenge+nameStart, "algorithm", 9) == 0)
|
||||
{
|
||||
// we want to clear the default, so we use = not |= here
|
||||
*algorithm = ALGO_SPECIFIED;
|
||||
if (valueLength == 3 &&
|
||||
nsCRT::strncasecmp(challenge+valueStart, "MD5", 3) == 0)
|
||||
*algorithm |= ALGO_MD5;
|
||||
else if (valueLength == 8 &&
|
||||
nsCRT::strncasecmp(challenge+valueStart, "MD5-sess", 8) == 0)
|
||||
*algorithm |= ALGO_MD5_SESS;
|
||||
}
|
||||
else if (nameLength == 3 &&
|
||||
nsCRT::strncasecmp(challenge+nameStart, "qop", 3) == 0)
|
||||
{
|
||||
PRInt16 ipos = valueStart;
|
||||
while (ipos < valueStart+valueLength) {
|
||||
while (ipos < valueStart+valueLength &&
|
||||
(nsCRT::IsAsciiSpace(challenge[ipos]) ||
|
||||
challenge[ipos] == ','))
|
||||
ipos++;
|
||||
PRInt16 algostart = ipos;
|
||||
while (ipos < valueStart+valueLength &&
|
||||
!nsCRT::IsAsciiSpace(challenge[ipos]) &&
|
||||
challenge[ipos] != ',')
|
||||
ipos++;
|
||||
if ((ipos - algostart) == 4 &&
|
||||
nsCRT::strncasecmp(challenge+algostart, "auth", 4) == 0)
|
||||
*qop |= QOP_AUTH;
|
||||
else if ((ipos - algostart) == 8 &&
|
||||
nsCRT::strncasecmp(challenge+algostart, "auth-int", 8) == 0)
|
||||
*qop |= QOP_AUTH_INT;
|
||||
}
|
||||
}
|
||||
}
|
||||
return NS_OK;
|
||||
}
|
|
@ -0,0 +1,100 @@
|
|||
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*-
|
||||
*
|
||||
* The contents of this file are subject to the Mozilla Public
|
||||
* License Version 1.1 (the "License"); you may not use this file
|
||||
* except in compliance with the License. You may obtain a copy of
|
||||
* the License at http://www.mozilla.org/MPL/
|
||||
*
|
||||
* Software distributed under the License is distributed on an "AS
|
||||
* IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
|
||||
* implied. See the License for the specific language governing
|
||||
* rights and limitations under the License.
|
||||
*
|
||||
* The Original Code is mozilla.org code.
|
||||
*
|
||||
* The Initial Developer of the Original Code is Netscape
|
||||
* Communications Corporation. Portions created by Netscape are
|
||||
* Copyright (C) 1998 Netscape Communications Corporation. All
|
||||
* Rights Reserved.
|
||||
*
|
||||
* Contributor(s):
|
||||
* Justin Bradford <jab@atdot.org> (original author of nsDigestAuth.h)
|
||||
* An-Cheng Huang <pach@cs.cmu.edu>
|
||||
* Darin Fisher <darin@netscape.com>
|
||||
*/
|
||||
|
||||
#ifndef nsDigestAuth_h__
|
||||
#define nsDigestAuth_h__
|
||||
|
||||
#include "nsIHttpAuthenticator.h"
|
||||
#include "nsISignatureVerifier.h"
|
||||
#include "nsString.h"
|
||||
#include "nsCOMPtr.h"
|
||||
|
||||
#define ALGO_SPECIFIED 0x01
|
||||
#define ALGO_MD5 0x02
|
||||
#define ALGO_MD5_SESS 0x04
|
||||
#define QOP_AUTH 0x01
|
||||
#define QOP_AUTH_INT 0x02
|
||||
|
||||
#define DIGEST_LENGTH 16
|
||||
#define EXPANDED_DIGEST_LENGTH 32
|
||||
#define NONCE_COUNT_LENGTH 8
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// nsHttpDigestAuth
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
class nsHttpDigestAuth : public nsIHttpAuthenticator
|
||||
{
|
||||
public:
|
||||
NS_DECL_ISUPPORTS
|
||||
NS_DECL_NSIHTTPAUTHENTICATOR
|
||||
|
||||
nsHttpDigestAuth();
|
||||
virtual ~nsHttpDigestAuth() {}
|
||||
|
||||
protected:
|
||||
nsresult ExpandToHex(const char * digest, char * result);
|
||||
|
||||
nsresult CalculateResponse(const char * ha1_digest,
|
||||
const char * ha2_digest,
|
||||
const nsAFlatCString & nonce,
|
||||
PRUint16 qop,
|
||||
const char * nonce_count,
|
||||
const nsAFlatCString & cnonce,
|
||||
char * result);
|
||||
|
||||
nsresult CalculateHA1(const nsAFlatCString & username,
|
||||
const nsAFlatCString & password,
|
||||
const nsAFlatCString & realm,
|
||||
PRUint16 algorithm,
|
||||
const nsAFlatCString & nonce,
|
||||
const nsAFlatCString & cnonce,
|
||||
char * result);
|
||||
|
||||
nsresult CalculateHA2(const nsAFlatCString & http_method,
|
||||
const nsAFlatCString & http_uri_path,
|
||||
PRUint16 qop,
|
||||
const char * body_digest,
|
||||
char * result);
|
||||
|
||||
nsresult ParseChallenge(const char * challenge,
|
||||
nsACString & realm,
|
||||
nsACString & domain,
|
||||
nsACString & nonce,
|
||||
nsACString & opaque,
|
||||
PRBool * stale,
|
||||
PRUint16 * algorithm,
|
||||
PRUint16 * qop);
|
||||
|
||||
// result is in mHashBuf
|
||||
nsresult MD5Hash(const char *buf, PRUint32 len);
|
||||
|
||||
protected:
|
||||
nsCOMPtr<nsISignatureVerifier> mVerifier;
|
||||
char mHashBuf[DIGEST_LENGTH];
|
||||
PRBool mGotVerifier;
|
||||
};
|
||||
|
||||
#endif // nsHttpDigestAuth_h__
|
Загрузка…
Ссылка в новой задаче