Backed out 14 changesets (bug 1705659, bug 472823, bug 669675) for causing bustages in nsHttpChannelAuthProvider.cpp

CLOSED TREE

Backed out changeset 42561f42313d (bug 669675)
Backed out changeset 2aee05c2d6f3 (bug 1705659)
Backed out changeset ff4348e0a307 (bug 1705659)
Backed out changeset 897868e22c81 (bug 1705659)
Backed out changeset c808bf01dfe8 (bug 1705659)
Backed out changeset 5c13ec25cc2e (bug 1705659)
Backed out changeset 4337214c8846 (bug 1705659)
Backed out changeset 18d3a604336a (bug 1705659)
Backed out changeset 3af362aa2b25 (bug 1705659)
Backed out changeset 36eff14cf2ea (bug 1705659)
Backed out changeset 8af29f96ac77 (bug 1705659)
Backed out changeset eab68e8bea29 (bug 1705659)
Backed out changeset 05492b6578a9 (bug 1705659)
Backed out changeset 3259a8cb3db1 (bug 472823)
This commit is contained in:
Alexandru Michis 2021-05-06 17:37:17 +03:00
Родитель c2369fc052
Коммит 574bea557a
24 изменённых файлов: 965 добавлений и 1501 удалений

Просмотреть файл

@ -192,10 +192,10 @@ static nsresult gssInit() {
LOG(("Attempting to load gss functions\n"));
for (auto& gssFunc : gssFuncs) {
gssFunc.func = PR_FindFunctionSymbol(lib, gssFunc.str);
if (!gssFunc.func) {
LOG(("Fail to load %s function from gssapi library\n", gssFunc.str));
for (size_t i = 0; i < ArrayLength(gssFuncs); ++i) {
gssFuncs[i].func = PR_FindFunctionSymbol(lib, gssFuncs[i].str);
if (!gssFuncs[i].func) {
LOG(("Fail to load %s function from gssapi library\n", gssFuncs[i].str));
PR_UnloadLibrary(lib);
return NS_ERROR_FAILURE;
}
@ -324,15 +324,14 @@ void nsAuthGSSAPI::Shutdown() {
NS_IMPL_ISUPPORTS(nsAuthGSSAPI, nsIAuthModule)
NS_IMETHODIMP
nsAuthGSSAPI::Init(const nsACString& serviceName, uint32_t serviceFlags,
const nsAString& domain, const nsAString& username,
const nsAString& password) {
nsAuthGSSAPI::Init(const char* serviceName, uint32_t serviceFlags,
const char16_t* domain, const char16_t* username,
const char16_t* password) {
// we don't expect to be passed any user credentials
NS_ASSERTION(domain.IsEmpty() && username.IsEmpty() && password.IsEmpty(),
"unexpected credentials");
NS_ASSERTION(!domain && !username && !password, "unexpected credentials");
// it's critial that the caller supply a service name to be used
NS_ENSURE_TRUE(!serviceName.IsEmpty(), NS_ERROR_INVALID_ARG);
NS_ENSURE_TRUE(serviceName && *serviceName, NS_ERROR_INVALID_ARG);
LOG(("entering nsAuthGSSAPI::Init()\n"));
@ -447,19 +446,17 @@ nsAuthGSSAPI::GetNextToken(const void* inToken, uint32_t inTokenLen,
}
*outTokenLen = output_token.length;
if (output_token.length != 0) {
if (output_token.length != 0)
*outToken = moz_xmemdup(output_token.value, output_token.length);
} else {
else
*outToken = nullptr;
}
gss_release_buffer_ptr(&minor_status, &output_token);
if (major_status == GSS_S_COMPLETE) {
if (major_status == GSS_S_COMPLETE)
rv = NS_SUCCESS_AUTH_FINISHED;
} else {
else
rv = NS_OK;
}
end:
gss_release_name_ptr(&minor_status, &server);
@ -491,11 +488,10 @@ nsAuthGSSAPI::Unwrap(const void* inToken, uint32_t inTokenLen, void** outToken,
*outTokenLen = output_token.length;
if (output_token.length) {
if (output_token.length)
*outToken = moz_xmemdup(output_token.value, output_token.length);
} else {
else
*outToken = nullptr;
}
gss_release_buffer_ptr(&minor_status, &output_token);

Просмотреть файл

@ -20,14 +20,13 @@ void nsAuthSASL::Reset() { mSASLReady = false; }
NS_IMPL_ISUPPORTS(nsAuthSASL, nsIAuthModule)
NS_IMETHODIMP
nsAuthSASL::Init(const nsACString& serviceName, uint32_t serviceFlags,
const nsAString& domain, const nsAString& username,
const nsAString& password) {
nsAuthSASL::Init(const char* serviceName, uint32_t serviceFlags,
const char16_t* domain, const char16_t* username,
const char16_t* password) {
nsresult rv;
NS_ASSERTION(!username.IsEmpty(), "SASL requires a username");
NS_ASSERTION(domain.IsEmpty() && password.IsEmpty(),
"unexpected credentials");
NS_ASSERTION(username, "SASL requires a username");
NS_ASSERTION(!domain && !password, "unexpected credentials");
mUsername = username;
@ -46,7 +45,7 @@ nsAuthSASL::Init(const nsACString& serviceName, uint32_t serviceFlags,
MOZ_ALWAYS_TRUE(mInnerModule = nsIAuthModule::CreateInstance(authType));
mInnerModule->Init(serviceName, serviceFlags, u""_ns, u""_ns, u""_ns);
mInnerModule->Init(serviceName, serviceFlags, nullptr, nullptr, nullptr);
return NS_OK;
}

Просмотреть файл

@ -90,7 +90,7 @@ static nsresult InitSSPI() {
//-----------------------------------------------------------------------------
nsresult nsAuthSSPI::MakeSN(const nsACString& principal, nsCString& result) {
nsresult nsAuthSSPI::MakeSN(const char* principal, nsCString& result) {
nsresult rv;
nsAutoCString buf(principal);
@ -174,9 +174,9 @@ void nsAuthSSPI::Reset() {
NS_IMPL_ISUPPORTS(nsAuthSSPI, nsIAuthModule)
NS_IMETHODIMP
nsAuthSSPI::Init(const nsACString& aServiceName, uint32_t aServiceFlags,
const nsAString& aDomain, const nsAString& aUsername,
const nsAString& aPassword) {
nsAuthSSPI::Init(const char* serviceName, uint32_t serviceFlags,
const char16_t* domain, const char16_t* username,
const char16_t* password) {
LOG((" nsAuthSSPI::Init\n"));
mIsFirst = true;
@ -185,7 +185,7 @@ nsAuthSSPI::Init(const nsACString& aServiceName, uint32_t aServiceFlags,
// The caller must supply a service name to be used. (For why we now require
// a service name for NTLM, see bug 487872.)
NS_ENSURE_TRUE(!aServiceName.IsEmpty(), NS_ERROR_INVALID_ARG);
NS_ENSURE_TRUE(serviceName && *serviceName, NS_ERROR_INVALID_ARG);
nsresult rv;
@ -203,18 +203,18 @@ nsAuthSSPI::Init(const nsACString& aServiceName, uint32_t aServiceFlags,
// lookups. The incoming serviceName is in the format: "protocol@hostname",
// SSPI expects
// "<service class>/<hostname>", so swap the '@' for a '/'.
mServiceName = aServiceName;
mServiceName.Assign(serviceName);
int32_t index = mServiceName.FindChar('@');
if (index == kNotFound) return NS_ERROR_UNEXPECTED;
mServiceName.Replace(index, 1, '/');
} else {
// Kerberos requires the canonical host, MakeSN takes care of this through a
// DNS lookup.
rv = MakeSN(aServiceName, mServiceName);
rv = MakeSN(serviceName, mServiceName);
if (NS_FAILED(rv)) return rv;
}
mServiceFlags = aServiceFlags;
mServiceFlags = serviceFlags;
SECURITY_STATUS rc;
@ -235,11 +235,11 @@ nsAuthSSPI::Init(const nsACString& aServiceName, uint32_t aServiceFlags,
// domain, username, and password will be null if nsHttpNTLMAuth's
// ChallengeReceived returns false for identityInvalid. Use default
// credentials in this case by passing null for pai.
if (!aUsername.IsEmpty() && !aPassword.IsEmpty()) {
if (username && password) {
// Keep a copy of these strings for the duration
mUsername = aUsername;
mPassword = aPassword;
mDomain = aDomain;
mUsername.Assign(username);
mPassword.Assign(password);
mDomain.Assign(domain);
ai.Domain = reinterpret_cast<unsigned short*>(mDomain.BeginWriting());
ai.DomainLength = mDomain.Length();
ai.User = reinterpret_cast<unsigned short*>(mUsername.BeginWriting());
@ -258,7 +258,7 @@ nsAuthSSPI::Init(const nsACString& aServiceName, uint32_t aServiceFlags,
static bool sTelemetrySent = false;
if (!sTelemetrySent) {
mozilla::Telemetry::Accumulate(mozilla::Telemetry::NTLM_MODULE_USED_2,
aServiceFlags & nsIAuthModule::REQ_PROXY_AUTH
serviceFlags & nsIAuthModule::REQ_PROXY_AUTH
? NTLM_MODULE_WIN_API_PROXY
: NTLM_MODULE_WIN_API_DIRECT);
sTelemetrySent = true;

Просмотреть файл

@ -41,7 +41,7 @@ class nsAuthSSPI final : public nsIAuthModule {
typedef ::TimeStamp MS_TimeStamp;
private:
nsresult MakeSN(const nsACString& principal, nsCString& result);
nsresult MakeSN(const char* principal, nsCString& result);
CredHandle mCred;
CtxtHandle mCtxt;

Просмотреть файл

@ -49,9 +49,8 @@ static bool SpawnIOChild(char* const* aArgs, PRProcess** aPID,
PRFileDesc** aFromChildFD, PRFileDesc** aToChildFD) {
PRFileDesc* toChildPipeRead;
PRFileDesc* toChildPipeWrite;
if (PR_CreatePipe(&toChildPipeRead, &toChildPipeWrite) != PR_SUCCESS) {
if (PR_CreatePipe(&toChildPipeRead, &toChildPipeWrite) != PR_SUCCESS)
return false;
}
PR_SetFDInheritable(toChildPipeRead, true);
PR_SetFDInheritable(toChildPipeWrite, false);
@ -190,11 +189,10 @@ nsresult nsAuthSambaNTLM::SpawnNTLMAuthHelper() {
}
NS_IMETHODIMP
nsAuthSambaNTLM::Init(const nsACString& serviceName, uint32_t serviceFlags,
const nsAString& domain, const nsAString& username,
const nsAString& password) {
NS_ASSERTION(username.IsEmpty() && domain.IsEmpty() && password.IsEmpty(),
"unexpected credentials");
nsAuthSambaNTLM::Init(const char* serviceName, uint32_t serviceFlags,
const char16_t* domain, const char16_t* username,
const char16_t* password) {
NS_ASSERTION(!username && !domain && !password, "unexpected credentials");
static bool sTelemetrySent = false;
if (!sTelemetrySent) {

Просмотреть файл

@ -42,7 +42,7 @@ class nsAuthSambaNTLM final : public nsIAuthModule {
void Shutdown();
uint8_t* mInitialMessage; /* free with free() */
uint32_t mInitialMessageLen{};
uint32_t mInitialMessageLen;
PRProcess* mChildPID;
PRFileDesc* mFromChildFD;
PRFileDesc* mToChildFD;

Просмотреть файл

@ -147,8 +147,7 @@ nsHttpNegotiateAuth::GetAuthFlags(uint32_t* flags) {
//
NS_IMETHODIMP
nsHttpNegotiateAuth::ChallengeReceived(nsIHttpAuthenticableChannel* authChannel,
const nsACString& challenge,
bool isProxyAuth,
const char* challenge, bool isProxyAuth,
nsISupports** sessionState,
nsISupports** continuationState,
bool* identityInvalid) {
@ -225,7 +224,7 @@ nsHttpNegotiateAuth::ChallengeReceived(nsIHttpAuthenticableChannel* authChannel,
MOZ_ALWAYS_TRUE(module = nsIAuthModule::CreateInstance(authType));
rv = module->Init(service, req_flags, u""_ns, u""_ns, u""_ns);
rv = module->Init(service.get(), req_flags, nullptr, nullptr, nullptr);
if (NS_FAILED(rv)) {
return rv;
@ -250,15 +249,22 @@ namespace {
//
class GetNextTokenCompleteEvent final : public nsIRunnable,
public nsICancelable {
virtual ~GetNextTokenCompleteEvent() {
if (mCreds) {
free(mCreds);
}
};
public:
NS_DECL_THREADSAFE_ISUPPORTS
explicit GetNextTokenCompleteEvent(nsIHttpAuthenticatorCallback* aCallback)
: mCallback(aCallback) {}
: mCallback(aCallback), mCreds(nullptr), mCancelled(false) {}
nsresult DispatchSuccess(const nsACString& aCreds, uint32_t aFlags,
already_AddRefed<nsISupports> aSessionState,
already_AddRefed<nsISupports> aContinuationState) {
NS_IMETHODIMP DispatchSuccess(
char* aCreds, uint32_t aFlags,
already_AddRefed<nsISupports> aSessionState,
already_AddRefed<nsISupports> aContinuationState) {
// Called from worker thread
MOZ_ASSERT(!NS_IsMainThread());
@ -270,8 +276,9 @@ class GetNextTokenCompleteEvent final : public nsIRunnable,
return NS_DispatchToMainThread(this, NS_DISPATCH_NORMAL);
}
nsresult DispatchError(already_AddRefed<nsISupports> aSessionState,
already_AddRefed<nsISupports> aContinuationState) {
NS_IMETHODIMP DispatchError(
already_AddRefed<nsISupports> aSessionState,
already_AddRefed<nsISupports> aContinuationState) {
// Called from worker thread
MOZ_ASSERT(!NS_IsMainThread());
@ -307,13 +314,11 @@ class GetNextTokenCompleteEvent final : public nsIRunnable,
}
private:
virtual ~GetNextTokenCompleteEvent() = default;
nsCOMPtr<nsIHttpAuthenticatorCallback> mCallback;
nsCString mCreds;
uint32_t mFlags = 0;
nsresult mResult = NS_OK;
bool mCancelled = false;
char* mCreds; // This class owns it, freed in destructor
uint32_t mFlags;
nsresult mResult;
bool mCancelled;
nsCOMPtr<nsISupports> mSessionState;
nsCOMPtr<nsISupports> mContinuationState;
};
@ -332,8 +337,8 @@ class GetNextTokenRunnable final : public mozilla::Runnable {
public:
GetNextTokenRunnable(
nsMainThreadPtrHandle<nsIHttpAuthenticableChannel>& authChannel,
const nsACString& challenge, bool isProxyAuth, const nsAString& domain,
const nsAString& username, const nsAString& password,
const char* challenge, bool isProxyAuth, const char16_t* domain,
const char16_t* username, const char16_t* password,
nsISupports* sessionState, nsISupports* continuationState,
GetNextTokenCompleteEvent* aCompleteEvent)
: mozilla::Runnable("GetNextTokenRunnable"),
@ -351,9 +356,9 @@ class GetNextTokenRunnable final : public mozilla::Runnable {
// Runs on worker thread
MOZ_ASSERT(!NS_IsMainThread());
nsCString creds;
char* creds;
uint32_t flags;
nsresult rv = ObtainCredentialsAndFlags(creds, &flags);
nsresult rv = ObtainCredentialsAndFlags(&creds, &flags);
// Passing session and continuation state this way to not touch
// referencing of the object that may not be thread safe.
@ -370,7 +375,7 @@ class GetNextTokenRunnable final : public mozilla::Runnable {
mContinuationState.forget());
}
NS_IMETHODIMP ObtainCredentialsAndFlags(nsCString& aCreds, uint32_t* aFlags) {
NS_IMETHODIMP ObtainCredentialsAndFlags(char** aCreds, uint32_t* aFlags) {
nsresult rv;
// Use negotiate service to call GenerateCredentials outside of main thread
@ -392,8 +397,9 @@ class GetNextTokenRunnable final : public mozilla::Runnable {
// Should any of the session or continuation states change inside
// this method, they must be threadsafe.
rv = authenticator->GenerateCredentials(
mAuthChannel, mChallenge, mIsProxyAuth, mDomain, mUsername, mPassword,
&sessionState, &continuationState, aFlags, aCreds);
mAuthChannel, mChallenge.get(), mIsProxyAuth, mDomain.get(),
mUsername.get(), mPassword.get(), &sessionState, &continuationState,
aFlags, aCreds);
if (mSessionState != sessionState) {
mSessionState = sessionState;
}
@ -420,9 +426,9 @@ class GetNextTokenRunnable final : public mozilla::Runnable {
NS_IMETHODIMP
nsHttpNegotiateAuth::GenerateCredentialsAsync(
nsIHttpAuthenticableChannel* authChannel,
nsIHttpAuthenticatorCallback* aCallback, const nsACString& challenge,
bool isProxyAuth, const nsAString& domain, const nsAString& username,
const nsAString& password, nsISupports* sessionState,
nsIHttpAuthenticatorCallback* aCallback, const char* challenge,
bool isProxyAuth, const char16_t* domain, const char16_t* username,
const char16_t* password, nsISupports* sessionState,
nsISupports* continuationState, nsICancelable** aCancelable) {
NS_ENSURE_ARG(aCallback);
NS_ENSURE_ARG_POINTER(aCancelable);
@ -453,10 +459,10 @@ nsHttpNegotiateAuth::GenerateCredentialsAsync(
//
NS_IMETHODIMP
nsHttpNegotiateAuth::GenerateCredentials(
nsIHttpAuthenticableChannel* authChannel, const nsACString& aChallenge,
bool isProxyAuth, const nsAString& domain, const nsAString& username,
const nsAString& password, nsISupports** sessionState,
nsISupports** continuationState, uint32_t* flags, nsACString& creds) {
nsIHttpAuthenticableChannel* authChannel, const char* challenge,
bool isProxyAuth, const char16_t* domain, const char16_t* username,
const char16_t* password, nsISupports** sessionState,
nsISupports** continuationState, uint32_t* flags, char** creds) {
// ChallengeReceived must have been called previously.
nsIAuthModule* module = (nsIAuthModule*)*continuationState;
NS_ENSURE_TRUE(module, NS_ERROR_NOT_INITIALIZED);
@ -464,11 +470,12 @@ nsHttpNegotiateAuth::GenerateCredentials(
*flags = USING_INTERNAL_IDENTITY;
LOG(("nsHttpNegotiateAuth::GenerateCredentials() [challenge=%s]\n",
aChallenge.BeginReading()));
challenge));
NS_ASSERTION(creds, "null param");
#ifdef DEBUG
bool isGssapiAuth = StringBeginsWith(aChallenge, "Negotiate"_ns,
nsCaseInsensitiveCStringComparator);
bool isGssapiAuth = !PL_strncasecmp(challenge, kNegotiate, kNegotiateLen);
NS_ASSERTION(isGssapiAuth, "Unexpected challenge");
#endif
@ -481,43 +488,43 @@ nsHttpNegotiateAuth::GenerateCredentials(
// generally *does* require multiple round-trips. Don't assume
// auth can be completed in just 1 call.
//
unsigned int len = strlen(challenge);
nsAutoCString inToken;
if (aChallenge.Length() > kNegotiateLen) {
nsDependentCSubstring challenge(aChallenge, kNegotiateLen);
uint32_t startPos = 0;
while (startPos < challenge.Length() && challenge[startPos] == ' ') {
startPos++;
}
if (startPos == challenge.Length()) {
return NS_ERROR_UNEXPECTED;
}
void *inToken = nullptr, *outToken;
uint32_t inTokenLen, outTokenLen;
if (len > kNegotiateLen) {
challenge += kNegotiateLen;
while (*challenge == ' ') challenge++;
len = strlen(challenge);
if (!len) return NS_ERROR_UNEXPECTED;
// strip off any padding (see bug 230351)
uint32_t len = challenge.Length();
while (len > startPos && challenge[len - 1] == '=') {
len--;
}
while (len && challenge[len - 1] == '=') len--;
//
// Decode the response that followed the "Negotiate" token
//
(void)Base64Decode(
nsDependentCSubstring(challenge, startPos, len - startPos), inToken);
nsresult rv = Base64Decode(challenge, len, (char**)&inToken, &inTokenLen);
if (NS_FAILED(rv)) {
free(inToken);
return rv;
}
} else {
//
// Initializing, don't use an input token.
//
inTokenLen = 0;
}
void* outToken = nullptr;
uint32_t outTokenLen = 0;
nsresult rv = module->GetNextToken(inToken.get(), inToken.Length(), &outToken,
&outTokenLen);
if (NS_FAILED(rv)) {
if (outToken) {
// Technically if the call fails we shouln't have allocated, but
// Coverity doesn't know that.
free(outToken);
}
return rv;
}
nsresult rv =
module->GetNextToken(inToken, inTokenLen, &outToken, &outTokenLen);
free(inToken);
if (NS_FAILED(rv)) return rv;
if (outTokenLen == 0) {
LOG((" No output token to send, exiting"));
@ -527,17 +534,20 @@ nsHttpNegotiateAuth::GenerateCredentials(
//
// base64 encode the output token.
//
nsAutoCString encodedToken;
rv = mozilla::Base64Encode(
nsDependentCSubstring((char*)outToken, outTokenLen), encodedToken);
char* encoded_token = PL_Base64Encode((char*)outToken, outTokenLen, nullptr);
free(outToken);
if (NS_FAILED(rv)) {
return rv;
}
if (!encoded_token) return NS_ERROR_OUT_OF_MEMORY;
LOG((" Sending a token of length %d\n", outTokenLen));
creds = nsPrintfCString("%s %s", kNegotiate, encodedToken.get());
// allocate a buffer sizeof("Negotiate" + " " + b64output_token + "\0")
const int bufsize = kNegotiateLen + 1 + strlen(encoded_token) + 1;
*creds = (char*)moz_xmalloc(bufsize);
snprintf(*creds, bufsize, "%s %s", kNegotiate, encoded_token);
PR_Free(encoded_token); // PL_Base64Encode() uses PR_Malloc().
return rv;
}

Просмотреть файл

@ -8736,12 +8736,6 @@
value: true
mirror: always
# Whether to use new implementation of ParseReasm
- name: network.auth.use_new_parse_realm
type: RelaxedAtomicBool
value: true
mirror: always
# See the full list of values in nsICookieService.idl.
- name: network.cookie.cookieBehavior
type: RelaxedAtomicInt32

Просмотреть файл

@ -15,7 +15,7 @@ class nsAuthInformationHolder : public nsIAuthInformation {
public:
// aAuthType must be ASCII
nsAuthInformationHolder(uint32_t aFlags, const nsString& aRealm,
const nsACString& aAuthType)
const nsCString& aAuthType)
: mFlags(aFlags), mRealm(aRealm), mAuthType(aAuthType) {}
NS_DECL_ISUPPORTS

Просмотреть файл

@ -60,11 +60,11 @@ interface nsIAuthModule : nsISupports
* @param aPassword
* the user's password
*/
void init(in ACString aServiceName,
void init(in string aServiceName,
in unsigned long aServiceFlags,
in AString aDomain,
in AString aUsername,
in AString aPassword);
in wstring aDomain,
in wstring aUsername,
in wstring aPassword);
/**
* Called to get the next token in a sequence of authentication steps.

Просмотреть файл

@ -21,7 +21,7 @@ interface nsIHttpAuthenticatorCallback : nsISupports
* @param aContinuationState
* Modified continuation state to be passed to caller
*/
void onCredsGenerated(in ACString aCreds,
void onCredsGenerated(in string aCreds,
in unsigned long aFlags,
in nsresult aResult,
in nsISupports aSessionsState,

Просмотреть файл

@ -22,7 +22,7 @@
namespace mozilla {
namespace net {
static inline void GetAuthKey(const nsACString& scheme, const nsACString& host,
static inline void GetAuthKey(const char* scheme, const char* host,
int32_t port, nsACString const& originSuffix,
nsCString& key) {
key.Truncate();
@ -35,6 +35,17 @@ static inline void GetAuthKey(const nsACString& scheme, const nsACString& host,
key.AppendInt(port);
}
// return true if the two strings are equal or both empty. an empty string
// is either null or zero length.
static bool StrEquivalent(const char16_t* a, const char16_t* b) {
static const char16_t emptyStr[] = {0};
if (!a) a = emptyStr;
if (!b) b = emptyStr;
return nsCRT::strcmp(a, b) == 0;
}
//-----------------------------------------------------------------------------
// nsHttpAuthCache <public>
//-----------------------------------------------------------------------------
@ -60,14 +71,12 @@ nsHttpAuthCache::~nsHttpAuthCache() {
}
}
nsresult nsHttpAuthCache::GetAuthEntryForPath(const nsACString& scheme,
const nsACString& host,
int32_t port,
const nsACString& path,
nsresult nsHttpAuthCache::GetAuthEntryForPath(const char* scheme,
const char* host, int32_t port,
const char* path,
nsACString const& originSuffix,
nsHttpAuthEntry** entry) {
LOG(("nsHttpAuthCache::GetAuthEntryForPath %p [path=%s]\n", this,
path.BeginReading()));
LOG(("nsHttpAuthCache::GetAuthEntryForPath %p [path=%s]\n", this, path));
nsAutoCString key;
nsHttpAuthNode* node = LookupAuthNode(scheme, host, port, originSuffix, key);
@ -78,16 +87,14 @@ nsresult nsHttpAuthCache::GetAuthEntryForPath(const nsACString& scheme,
return *entry ? NS_OK : NS_ERROR_NOT_AVAILABLE;
}
nsresult nsHttpAuthCache::GetAuthEntryForDomain(const nsACString& scheme,
const nsACString& host,
int32_t port,
const nsACString& realm,
nsresult nsHttpAuthCache::GetAuthEntryForDomain(const char* scheme,
const char* host, int32_t port,
const char* realm,
nsACString const& originSuffix,
nsHttpAuthEntry** entry)
{
LOG(("nsHttpAuthCache::GetAuthEntryForDomain %p [realm=%s]\n", this,
realm.BeginReading()));
LOG(("nsHttpAuthCache::GetAuthEntryForDomain %p [realm=%s]\n", this, realm));
nsAutoCString key;
nsHttpAuthNode* node = LookupAuthNode(scheme, host, port, originSuffix, key);
@ -98,15 +105,17 @@ nsresult nsHttpAuthCache::GetAuthEntryForDomain(const nsACString& scheme,
return *entry ? NS_OK : NS_ERROR_NOT_AVAILABLE;
}
nsresult nsHttpAuthCache::SetAuthEntry(
const nsACString& scheme, const nsACString& host, int32_t port,
const nsACString& path, const nsACString& realm, const nsACString& creds,
const nsACString& challenge, nsACString const& originSuffix,
const nsHttpAuthIdentity* ident, nsISupports* metadata) {
nsresult nsHttpAuthCache::SetAuthEntry(const char* scheme, const char* host,
int32_t port, const char* path,
const char* realm, const char* creds,
const char* challenge,
nsACString const& originSuffix,
const nsHttpAuthIdentity* ident,
nsISupports* metadata) {
nsresult rv;
LOG(("nsHttpAuthCache::SetAuthEntry %p [realm=%s path=%s metadata=%p]\n",
this, realm.BeginReading(), path.BeginReading(), metadata));
this, realm, path, metadata));
nsAutoCString key;
nsHttpAuthNode* node = LookupAuthNode(scheme, host, port, originSuffix, key);
@ -127,9 +136,8 @@ nsresult nsHttpAuthCache::SetAuthEntry(
return node->SetAuthEntry(path, realm, creds, challenge, ident, metadata);
}
void nsHttpAuthCache::ClearAuthEntry(const nsACString& scheme,
const nsACString& host, int32_t port,
const nsACString& realm,
void nsHttpAuthCache::ClearAuthEntry(const char* scheme, const char* host,
int32_t port, const char* realm,
nsACString const& originSuffix) {
nsAutoCString key;
GetAuthKey(scheme, host, port, originSuffix, key);
@ -146,9 +154,8 @@ void nsHttpAuthCache::ClearAll() {
// nsHttpAuthCache <private>
//-----------------------------------------------------------------------------
nsHttpAuthNode* nsHttpAuthCache::LookupAuthNode(const nsACString& scheme,
const nsACString& host,
int32_t port,
nsHttpAuthNode* nsHttpAuthCache::LookupAuthNode(const char* scheme,
const char* host, int32_t port,
nsACString const& originSuffix,
nsCString& key) {
GetAuthKey(scheme, host, port, originSuffix, key);
@ -208,55 +215,153 @@ void nsHttpAuthCache::CollectKeys(nsTArray<nsCString>& aValue) {
// nsHttpAuthIdentity
//-----------------------------------------------------------------------------
nsresult nsHttpAuthIdentity::Set(const char16_t* domain, const char16_t* user,
const char16_t* pass) {
char16_t *newUser, *newPass, *newDomain;
int domainLen = domain ? NS_strlen(domain) : 0;
int userLen = user ? NS_strlen(user) : 0;
int passLen = pass ? NS_strlen(pass) : 0;
int len = userLen + 1 + passLen + 1 + domainLen + 1;
newUser = (char16_t*)malloc(len * sizeof(char16_t));
if (!newUser) return NS_ERROR_OUT_OF_MEMORY;
if (user) memcpy(newUser, user, userLen * sizeof(char16_t));
newUser[userLen] = 0;
newPass = &newUser[userLen + 1];
if (pass) memcpy(newPass, pass, passLen * sizeof(char16_t));
newPass[passLen] = 0;
newDomain = &newPass[passLen + 1];
if (domain) memcpy(newDomain, domain, domainLen * sizeof(char16_t));
newDomain[domainLen] = 0;
// wait until the end to clear member vars in case input params
// reference our members!
if (mUser) free(mUser);
mUser = newUser;
mPass = newPass;
mDomain = newDomain;
return NS_OK;
}
void nsHttpAuthIdentity::Clear() {
mUser.Truncate();
mPass.Truncate();
mDomain.Truncate();
if (mUser) {
free(mUser);
mUser = nullptr;
mPass = nullptr;
mDomain = nullptr;
}
}
bool nsHttpAuthIdentity::Equals(const nsHttpAuthIdentity& ident) const {
// we could probably optimize this with a single loop, but why bother?
return mUser == ident.mUser && mPass == ident.mPass &&
mDomain == ident.mDomain;
return StrEquivalent(mUser, ident.mUser) &&
StrEquivalent(mPass, ident.mPass) &&
StrEquivalent(mDomain, ident.mDomain);
}
//-----------------------------------------------------------------------------
// nsHttpAuthEntry
//-----------------------------------------------------------------------------
nsresult nsHttpAuthEntry::AddPath(const nsACString& aPath) {
for (const auto& p : mPaths) {
if (StringBeginsWith(aPath, p)) {
nsHttpAuthEntry::~nsHttpAuthEntry() {
if (mRealm) free(mRealm);
while (mRoot) {
nsHttpAuthPath* ap = mRoot;
mRoot = mRoot->mNext;
free(ap);
}
}
nsresult nsHttpAuthEntry::AddPath(const char* aPath) {
// null path matches empty path
if (!aPath) aPath = "";
nsHttpAuthPath* tempPtr = mRoot;
while (tempPtr) {
const char* curpath = tempPtr->mPath;
if (strncmp(aPath, curpath, strlen(curpath)) == 0)
return NS_OK; // subpath already exists in the list
}
tempPtr = tempPtr->mNext;
}
mPaths.AppendElement(aPath);
// Append the aPath
nsHttpAuthPath* newAuthPath;
int newpathLen = strlen(aPath);
newAuthPath = (nsHttpAuthPath*)malloc(sizeof(nsHttpAuthPath) + newpathLen);
if (!newAuthPath) return NS_ERROR_OUT_OF_MEMORY;
memcpy(newAuthPath->mPath, aPath, newpathLen + 1);
newAuthPath->mNext = nullptr;
if (!mRoot)
mRoot = newAuthPath; // first entry
else
mTail->mNext = newAuthPath; // Append newAuthPath
// update the tail pointer.
mTail = newAuthPath;
return NS_OK;
}
nsresult nsHttpAuthEntry::Set(const nsACString& path, const nsACString& realm,
const nsACString& creds, const nsACString& chall,
nsresult nsHttpAuthEntry::Set(const char* path, const char* realm,
const char* creds, const char* chall,
const nsHttpAuthIdentity* ident,
nsISupports* metadata) {
char *newRealm, *newCreds, *newChall;
int realmLen = realm ? strlen(realm) : 0;
int credsLen = creds ? strlen(creds) : 0;
int challLen = chall ? strlen(chall) : 0;
int len = realmLen + 1 + credsLen + 1 + challLen + 1;
newRealm = (char*)malloc(len);
if (!newRealm) return NS_ERROR_OUT_OF_MEMORY;
if (realm) memcpy(newRealm, realm, realmLen);
newRealm[realmLen] = 0;
newCreds = &newRealm[realmLen + 1];
if (creds) memcpy(newCreds, creds, credsLen);
newCreds[credsLen] = 0;
newChall = &newCreds[credsLen + 1];
if (chall) memcpy(newChall, chall, challLen);
newChall[challLen] = 0;
nsresult rv = NS_OK;
if (ident) {
mIdent = *ident;
rv = mIdent.Set(*ident);
} else if (mIdent.IsEmpty()) {
// If we are not given an identity and our cached identity has not been
// initialized yet (so is currently empty), initialize it now by
// filling it with nulls. We need to do that because consumers expect
// that mIdent is initialized after this function returns.
mIdent.Clear();
rv = mIdent.Set(nullptr, nullptr, nullptr);
}
nsresult rv = AddPath(path);
if (NS_FAILED(rv)) {
free(newRealm);
return rv;
}
mRealm = realm;
mCreds = creds;
mChallenge = chall;
rv = AddPath(path);
if (NS_FAILED(rv)) {
free(newRealm);
return rv;
}
// wait until the end to clear member vars in case input params
// reference our members!
if (mRealm) free(mRealm);
mRealm = newRealm;
mCreds = newCreds;
mChallenge = newChall;
mMetaData = metadata;
return NS_OK;
@ -276,36 +381,45 @@ nsHttpAuthNode::~nsHttpAuthNode() {
mList.Clear();
}
nsHttpAuthEntry* nsHttpAuthNode::LookupEntryByPath(const nsACString& aPath) {
nsHttpAuthEntry* nsHttpAuthNode::LookupEntryByPath(const char* path) {
// null path matches empty path
if (!path) path = "";
// look for an entry that either matches or contains this directory.
// ie. we'll give out credentials if the given directory is a sub-
// directory of an existing entry.
for (uint32_t i = 0; i < mList.Length(); ++i) {
const auto& entry = mList[i];
for (const auto& entryPath : entry->mPaths) {
nsHttpAuthPath* authPath = entry->RootPath();
while (authPath) {
const char* entryPath = authPath->mPath;
// proxy auth entries have no path, so require exact match on
// empty path string.
if (entryPath.IsEmpty()) {
if (aPath.IsEmpty()) {
if (entryPath[0] == '\0') {
if (path[0] == '\0') {
return entry.get();
}
} else if (StringBeginsWith(aPath, entryPath)) {
} else if (strncmp(path, entryPath, strlen(entryPath)) == 0) {
return entry.get();
}
authPath = authPath->mNext;
}
}
return nullptr;
}
nsHttpAuthNode::EntryList::const_iterator nsHttpAuthNode::LookupEntryItrByRealm(
const nsACString& realm) const {
const char* realm) const {
// null realm matches empty realm
if (!realm) realm = "";
return std::find_if(mList.cbegin(), mList.cend(), [&realm](const auto& val) {
return realm.Equals(val->Realm());
return strcmp(realm, val->Realm()) == 0;
});
}
nsHttpAuthEntry* nsHttpAuthNode::LookupEntryByRealm(const nsACString& realm) {
nsHttpAuthEntry* nsHttpAuthNode::LookupEntryByRealm(const char* realm) {
auto itr = LookupEntryItrByRealm(realm);
if (itr != mList.cend()) {
return itr->get();
@ -314,10 +428,8 @@ nsHttpAuthEntry* nsHttpAuthNode::LookupEntryByRealm(const nsACString& realm) {
return nullptr;
}
nsresult nsHttpAuthNode::SetAuthEntry(const nsACString& path,
const nsACString& realm,
const nsACString& creds,
const nsACString& challenge,
nsresult nsHttpAuthNode::SetAuthEntry(const char* path, const char* realm,
const char* creds, const char* challenge,
const nsHttpAuthIdentity* ident,
nsISupports* metadata) {
// look for an entry with a matching realm
@ -338,7 +450,7 @@ nsresult nsHttpAuthNode::SetAuthEntry(const nsACString& path,
return NS_OK;
}
void nsHttpAuthNode::ClearAuthEntry(const nsACString& realm) {
void nsHttpAuthNode::ClearAuthEntry(const char* realm) {
auto idx = LookupEntryItrByRealm(realm);
if (idx != mList.cend()) {
mList.RemoveElementAt(idx);

Просмотреть файл

@ -20,33 +20,45 @@ class OriginAttributesPattern;
namespace net {
struct nsHttpAuthPath {
struct nsHttpAuthPath* mNext;
char mPath[1];
};
//-----------------------------------------------------------------------------
// nsHttpAuthIdentity
//-----------------------------------------------------------------------------
class nsHttpAuthIdentity {
public:
nsHttpAuthIdentity() = default;
nsHttpAuthIdentity(const nsAString& domain, const nsAString& user,
const nsAString& password)
: mUser(user), mPass(password), mDomain(domain) {}
nsHttpAuthIdentity() : mUser(nullptr), mPass(nullptr), mDomain(nullptr) {}
nsHttpAuthIdentity(const char16_t* domain, const char16_t* user,
const char16_t* password)
: mUser(nullptr), mPass{nullptr}, mDomain{nullptr} {
DebugOnly<nsresult> rv = Set(domain, user, password);
MOZ_ASSERT(NS_SUCCEEDED(rv));
}
~nsHttpAuthIdentity() { Clear(); }
const nsString& Domain() const { return mDomain; }
const nsString& User() const { return mUser; }
const nsString& Password() const { return mPass; }
const char16_t* Domain() const { return mDomain; }
const char16_t* User() const { return mUser; }
const char16_t* Password() const { return mPass; }
[[nodiscard]] nsresult Set(const char16_t* domain, const char16_t* user,
const char16_t* password);
[[nodiscard]] nsresult Set(const nsHttpAuthIdentity& other) {
return Set(other.mDomain, other.mUser, other.mPass);
}
void Clear();
bool Equals(const nsHttpAuthIdentity& ident) const;
bool IsEmpty() const {
return mUser.IsEmpty() && mPass.IsEmpty() && mDomain.IsEmpty();
}
bool Equals(const nsHttpAuthIdentity& other) const;
bool IsEmpty() const { return !mUser; }
private:
nsString mUser;
nsString mPass;
nsString mDomain;
// allocated as one contiguous blob, starting at mUser.
char16_t* mUser;
char16_t* mPass;
char16_t* mDomain;
};
//-----------------------------------------------------------------------------
@ -55,42 +67,49 @@ class nsHttpAuthIdentity {
class nsHttpAuthEntry {
public:
const nsCString& Realm() const { return mRealm; }
const nsCString& Creds() const { return mCreds; }
const nsCString& Challenge() const { return mChallenge; }
const nsString& Domain() const { return mIdent.Domain(); }
const nsString& User() const { return mIdent.User(); }
const nsString& Pass() const { return mIdent.Password(); }
const char* Realm() const { return mRealm; }
const char* Creds() const { return mCreds; }
const char* Challenge() const { return mChallenge; }
const char16_t* Domain() const { return mIdent.Domain(); }
const char16_t* User() const { return mIdent.User(); }
const char16_t* Pass() const { return mIdent.Password(); }
nsHttpAuthPath* RootPath() { return mRoot; }
const nsHttpAuthIdentity& Identity() const { return mIdent; }
[[nodiscard]] nsresult AddPath(const nsACString& aPath);
[[nodiscard]] nsresult AddPath(const char* aPath);
nsCOMPtr<nsISupports> mMetaData;
private:
nsHttpAuthEntry(const nsACString& path, const nsACString& realm,
const nsACString& creds, const nsACString& challenge,
const nsHttpAuthIdentity* ident, nsISupports* metadata) {
nsHttpAuthEntry(const char* path, const char* realm, const char* creds,
const char* challenge, const nsHttpAuthIdentity* ident,
nsISupports* metadata)
: mRoot(nullptr),
mTail(nullptr),
mRealm(nullptr),
mCreds{nullptr},
mChallenge{nullptr} {
DebugOnly<nsresult> rv =
Set(path, realm, creds, challenge, ident, metadata);
MOZ_ASSERT(NS_SUCCEEDED(rv));
}
~nsHttpAuthEntry() = default;
~nsHttpAuthEntry();
[[nodiscard]] nsresult Set(const nsACString& path, const nsACString& realm,
const nsACString& creds,
const nsACString& challenge,
[[nodiscard]] nsresult Set(const char* path, const char* realm,
const char* creds, const char* challenge,
const nsHttpAuthIdentity* ident,
nsISupports* metadata);
nsHttpAuthIdentity mIdent;
nsTArray<nsCString> mPaths;
nsHttpAuthPath* mRoot; // root pointer
nsHttpAuthPath* mTail; // tail pointer
nsCString mRealm;
nsCString mCreds;
nsCString mChallenge;
// allocated together in one blob, starting with mRealm.
char* mRealm;
char* mCreds;
char* mChallenge;
friend class nsHttpAuthNode;
friend class nsHttpAuthCache;
@ -111,22 +130,20 @@ class nsHttpAuthNode {
// path can be null, in which case we'll search for an entry
// with a null path.
nsHttpAuthEntry* LookupEntryByPath(const nsACString& path);
nsHttpAuthEntry* LookupEntryByPath(const char* path);
// realm must not be null
nsHttpAuthEntry* LookupEntryByRealm(const nsACString& realm);
EntryList::const_iterator LookupEntryItrByRealm(
const nsACString& realm) const;
nsHttpAuthEntry* LookupEntryByRealm(const char* realm);
EntryList::const_iterator LookupEntryItrByRealm(const char* realm) const;
// if a matching entry is found, then credentials will be changed.
[[nodiscard]] nsresult SetAuthEntry(const nsACString& path,
const nsACString& realm,
const nsACString& creds,
const nsACString& challenge,
[[nodiscard]] nsresult SetAuthEntry(const char* path, const char* realm,
const char* credentials,
const char* challenge,
const nsHttpAuthIdentity* ident,
nsISupports* metadata);
void ClearAuthEntry(const nsACString& realm);
void ClearAuthEntry(const char* realm);
uint32_t EntryCount() { return mList.Length(); }
@ -151,20 +168,18 @@ class nsHttpAuthCache {
// |scheme|, |host|, and |port| are required
// |path| can be null
// |entry| is either null or a weak reference
[[nodiscard]] nsresult GetAuthEntryForPath(const nsACString& scheme,
const nsACString& host,
int32_t port,
const nsACString& path,
[[nodiscard]] nsresult GetAuthEntryForPath(const char* scheme,
const char* host, int32_t port,
const char* path,
nsACString const& originSuffix,
nsHttpAuthEntry** entry);
// |scheme|, |host|, and |port| are required
// |realm| must not be null
// |entry| is either null or a weak reference
[[nodiscard]] nsresult GetAuthEntryForDomain(const nsACString& scheme,
const nsACString& host,
int32_t port,
const nsACString& realm,
[[nodiscard]] nsresult GetAuthEntryForDomain(const char* scheme,
const char* host, int32_t port,
const char* realm,
nsACString const& originSuffix,
nsHttpAuthEntry** entry);
@ -174,14 +189,13 @@ class nsHttpAuthCache {
// if |credentials|, |user|, |pass|, and |challenge| are each
// null, then the entry is deleted.
[[nodiscard]] nsresult SetAuthEntry(
const nsACString& scheme, const nsACString& host, int32_t port,
const nsACString& path, const nsACString& realm, const nsACString& creds,
const nsACString& challenge, nsACString const& originSuffix,
const nsHttpAuthIdentity* ident, nsISupports* metadata);
const char* scheme, const char* host, int32_t port, const char* directory,
const char* realm, const char* credentials, const char* challenge,
nsACString const& originSuffix, const nsHttpAuthIdentity* ident,
nsISupports* metadata);
void ClearAuthEntry(const nsACString& scheme, const nsACString& host,
int32_t port, const nsACString& realm,
nsACString const& originSuffix);
void ClearAuthEntry(const char* scheme, const char* host, int32_t port,
const char* realm, nsACString const& originSuffix);
// expire all existing auth list entries including proxy auths.
void ClearAll();
@ -190,9 +204,8 @@ class nsHttpAuthCache {
void CollectKeys(nsTArray<nsCString>& aValue);
private:
nsHttpAuthNode* LookupAuthNode(const nsACString& scheme,
const nsACString& host, int32_t port,
nsACString const& originSuffix,
nsHttpAuthNode* LookupAuthNode(const char* scheme, const char* host,
int32_t port, nsACString const& originSuffix,
nsCString& key);
class OriginClearObserver : public nsIObserver {

Просмотреть файл

@ -58,13 +58,14 @@ nsHttpAuthManager::GetAuthIdentity(
aPrincipal->OriginAttributesRef().CreateSuffix(originSuffix);
}
if (!aPath.IsEmpty()) {
rv = auth_cache->GetAuthEntryForPath(aScheme, aHost, aPort, aPath,
originSuffix, &entry);
} else {
rv = auth_cache->GetAuthEntryForDomain(aScheme, aHost, aPort, aRealm,
originSuffix, &entry);
}
if (!aPath.IsEmpty())
rv = auth_cache->GetAuthEntryForPath(
PromiseFlatCString(aScheme).get(), PromiseFlatCString(aHost).get(),
aPort, PromiseFlatCString(aPath).get(), originSuffix, &entry);
else
rv = auth_cache->GetAuthEntryForDomain(
PromiseFlatCString(aScheme).get(), PromiseFlatCString(aHost).get(),
aPort, PromiseFlatCString(aRealm).get(), originSuffix, &entry);
if (NS_FAILED(rv)) return rv;
if (!entry) return NS_ERROR_UNEXPECTED;
@ -82,7 +83,9 @@ nsHttpAuthManager::SetAuthIdentity(
const nsACString& aPath, const nsAString& aUserDomain,
const nsAString& aUserName, const nsAString& aUserPassword, bool aIsPrivate,
nsIPrincipal* aPrincipal) {
nsHttpAuthIdentity ident(aUserDomain, aUserName, aUserPassword);
nsHttpAuthIdentity ident(PromiseFlatString(aUserDomain).get(),
PromiseFlatString(aUserName).get(),
PromiseFlatString(aUserPassword).get());
nsAutoCString originSuffix;
if (aPrincipal) {
@ -90,11 +93,13 @@ nsHttpAuthManager::SetAuthIdentity(
}
nsHttpAuthCache* auth_cache = aIsPrivate ? mPrivateAuthCache : mAuthCache;
return auth_cache->SetAuthEntry(aScheme, aHost, aPort, aPath, aRealm,
""_ns, // credentials
""_ns, // challenge
originSuffix, &ident,
nullptr); // metadata
return auth_cache->SetAuthEntry(
PromiseFlatCString(aScheme).get(), PromiseFlatCString(aHost).get(), aPort,
PromiseFlatCString(aPath).get(), PromiseFlatCString(aRealm).get(),
nullptr, // credentials
nullptr, // challenge
originSuffix, &ident,
nullptr); // metadata
}
NS_IMETHODIMP

Просмотреть файл

@ -43,8 +43,8 @@ NS_IMPL_ISUPPORTS(nsHttpBasicAuth, nsIHttpAuthenticator)
NS_IMETHODIMP
nsHttpBasicAuth::ChallengeReceived(nsIHttpAuthenticableChannel* authChannel,
const nsACString& challenge,
bool isProxyAuth, nsISupports** sessionState,
const char* challenge, bool isProxyAuth,
nsISupports** sessionState,
nsISupports** continuationState,
bool* identityInvalid) {
// if challenged, then the username:password that was sent must
@ -55,40 +55,42 @@ nsHttpBasicAuth::ChallengeReceived(nsIHttpAuthenticableChannel* authChannel,
NS_IMETHODIMP
nsHttpBasicAuth::GenerateCredentialsAsync(
nsIHttpAuthenticableChannel* authChannel,
nsIHttpAuthenticatorCallback* aCallback, const nsACString& aChallenge,
bool isProxyAuth, const nsAString& domain, const nsAString& username,
const nsAString& password, nsISupports* sessionState,
nsIHttpAuthenticatorCallback* aCallback, const char* challenge,
bool isProxyAuth, const char16_t* domain, const char16_t* username,
const char16_t* password, nsISupports* sessionState,
nsISupports* continuationState, nsICancelable** aCancellable) {
return NS_ERROR_NOT_IMPLEMENTED;
}
NS_IMETHODIMP
nsHttpBasicAuth::GenerateCredentials(
nsIHttpAuthenticableChannel* authChannel, const nsACString& aChallenge,
bool isProxyAuth, const nsAString& domain, const nsAString& user,
const nsAString& password, nsISupports** sessionState,
nsISupports** continuationState, uint32_t* aFlags, nsACString& creds) {
LOG(("nsHttpBasicAuth::GenerateCredentials [challenge=%s]\n",
aChallenge.BeginReading()));
nsIHttpAuthenticableChannel* authChannel, const char* challenge,
bool isProxyAuth, const char16_t* domain, const char16_t* user,
const char16_t* password, nsISupports** sessionState,
nsISupports** continuationState, uint32_t* aFlags, char** creds)
{
LOG(("nsHttpBasicAuth::GenerateCredentials [challenge=%s]\n", challenge));
NS_ENSURE_ARG_POINTER(creds);
*aFlags = 0;
// we only know how to deal with Basic auth for http.
bool isBasicAuth = StringBeginsWith(aChallenge, "basic"_ns,
nsCaseInsensitiveCStringComparator);
bool isBasicAuth = !nsCRT::strncasecmp(challenge, "basic", 5);
NS_ENSURE_TRUE(isBasicAuth, NS_ERROR_UNEXPECTED);
// we work with UTF-8 around here
nsAutoCString userpass;
CopyUTF16toUTF8(user, userpass);
CopyUTF16toUTF8(mozilla::MakeStringSpan(user), userpass);
userpass.Append(':'); // always send a ':' (see bug 129565)
AppendUTF16toUTF8(password, userpass);
AppendUTF16toUTF8(mozilla::MakeStringSpan(password), userpass);
nsAutoCString authString{"Basic "_ns};
nsresult rv = Base64EncodeAppend(userpass, authString);
NS_ENSURE_SUCCESS(rv, rv);
creds = authString;
*creds = ToNewCString(authString);
return NS_OK;
}

Просмотреть файл

@ -10,7 +10,6 @@
#include "mozilla/BasePrincipal.h"
#include "mozilla/Preferences.h"
#include "mozilla/StoragePrincipalHelper.h"
#include "mozilla/Tokenizer.h"
#include "nsHttpChannelAuthProvider.h"
#include "nsCRT.h"
#include "nsNetUtil.h"
@ -77,7 +76,14 @@ static void GetOriginAttributesSuffix(nsIChannel* aChan, nsACString& aSuffix) {
}
nsHttpChannelAuthProvider::nsHttpChannelAuthProvider()
: mProxyAuth(false),
: mAuthChannel(nullptr),
mPort(-1),
mUsingSSL(false),
mProxyUsingSSL(false),
mIsPrivate(false),
mProxyAuthContinuationState(nullptr),
mAuthContinuationState(nullptr),
mProxyAuth(false),
mTriedProxyAuth(false),
mTriedHostAuth(false),
mSuppressDefensiveAuth(false),
@ -174,23 +180,21 @@ nsHttpChannelAuthProvider::ProcessAuthentication(uint32_t httpStatus,
return NS_ERROR_UNEXPECTED;
}
rv = mAuthChannel->GetProxyChallenges(challenges);
} else {
} else
rv = mAuthChannel->GetWWWChallenges(challenges);
}
if (NS_FAILED(rv)) return rv;
nsAutoCString creds;
rv = GetCredentials(challenges, mProxyAuth, creds);
rv = GetCredentials(challenges.get(), mProxyAuth, creds);
if (rv == NS_ERROR_IN_PROGRESS) return rv;
if (NS_FAILED(rv)) {
if (NS_FAILED(rv))
LOG(("unable to authenticate\n"));
} else {
else {
// set the authentication credentials
if (mProxyAuth) {
if (mProxyAuth)
rv = mAuthChannel->SetProxyCredentials(creds);
} else {
else
rv = mAuthChannel->SetWWWCredentials(creds);
}
}
return rv;
}
@ -221,10 +225,11 @@ nsHttpChannelAuthProvider::AddAuthorizationHeaders(
nsHttpAuthCache* authCache = gHttpHandler->AuthCache(mIsPrivate);
// check if proxy credentials should be sent
if (!ProxyHost().IsEmpty() && UsingHttpProxy()) {
SetAuthorizationHeader(authCache, nsHttp::Proxy_Authorization, "http"_ns,
ProxyHost(), ProxyPort(),
""_ns, // proxy has no path
const char* proxyHost = ProxyHost();
if (proxyHost && UsingHttpProxy()) {
SetAuthorizationHeader(authCache, nsHttp::Proxy_Authorization, "http",
proxyHost, ProxyPort(),
nullptr, // proxy has no path
mProxyIdent);
}
@ -244,8 +249,8 @@ nsHttpChannelAuthProvider::AddAuthorizationHeaders(
nsAutoCString path, scheme;
if (NS_SUCCEEDED(GetCurrentPath(path)) &&
NS_SUCCEEDED(mURI->GetScheme(scheme))) {
SetAuthorizationHeader(authCache, nsHttp::Authorization, scheme, Host(),
Port(), path, mIdent);
SetAuthorizationHeader(authCache, nsHttp::Authorization, scheme.get(),
Host(), Port(), path.get(), mIdent);
}
return NS_OK;
@ -310,34 +315,55 @@ nsHttpChannelAuthProvider::Disconnect(nsresult status) {
return NS_OK;
}
// buf contains "domain\user"
static void ParseUserDomain(char16_t* buf, const char16_t** user,
const char16_t** domain) {
char16_t* p = buf;
while (*p && *p != '\\') ++p;
if (!*p) return;
*p = '\0';
*domain = buf;
*user = p + 1;
}
// helper function for setting identity from raw user:pass
static void SetIdent(nsHttpAuthIdentity& ident, uint32_t authFlags,
char16_t* userBuf, char16_t* passBuf) {
const char16_t* user = userBuf;
const char16_t* domain = nullptr;
if (authFlags & nsIHttpAuthenticator::IDENTITY_INCLUDES_DOMAIN)
ParseUserDomain(userBuf, &user, &domain);
DebugOnly<nsresult> rv = ident.Set(domain, user, passBuf);
MOZ_ASSERT(NS_SUCCEEDED(rv));
}
// helper function for getting an auth prompt from an interface requestor
static void GetAuthPrompt(nsIInterfaceRequestor* ifreq, bool proxyAuth,
nsIAuthPrompt2** result) {
if (!ifreq) return;
uint32_t promptReason;
if (proxyAuth) {
if (proxyAuth)
promptReason = nsIAuthPromptProvider::PROMPT_PROXY;
} else {
else
promptReason = nsIAuthPromptProvider::PROMPT_NORMAL;
}
nsCOMPtr<nsIAuthPromptProvider> promptProvider = do_GetInterface(ifreq);
if (promptProvider) {
if (promptProvider)
promptProvider->GetAuthPrompt(promptReason, NS_GET_IID(nsIAuthPrompt2),
reinterpret_cast<void**>(result));
} else {
else
NS_QueryAuthPrompt2(ifreq, result);
}
}
// generate credentials for the given challenge, and update the auth cache.
nsresult nsHttpChannelAuthProvider::GenCredsAndSetEntry(
nsIHttpAuthenticator* auth, bool proxyAuth, const nsACString& scheme,
const nsACString& host, int32_t port, const nsACString& directory,
const nsACString& realm, const nsACString& challenge,
const nsHttpAuthIdentity& ident, nsCOMPtr<nsISupports>& sessionState,
nsACString& result) {
nsIHttpAuthenticator* auth, bool proxyAuth, const char* scheme,
const char* host, int32_t port, const char* directory, const char* realm,
const char* challenge, const nsHttpAuthIdentity& ident,
nsCOMPtr<nsISupports>& sessionState, char** result) {
nsresult rv;
nsISupports* ss = sessionState;
@ -372,18 +398,17 @@ nsresult nsHttpChannelAuthProvider::GenCredsAndSetEntry(
// don't log this in release build since it could contain sensitive info.
#ifdef DEBUG
LOG(("generated creds: %s\n", result.BeginReading()));
LOG(("generated creds: %s\n", *result));
#endif
return UpdateCache(auth, scheme, host, port, directory, realm, challenge,
ident, result, generateFlags, sessionState, proxyAuth);
ident, *result, generateFlags, sessionState, proxyAuth);
}
nsresult nsHttpChannelAuthProvider::UpdateCache(
nsIHttpAuthenticator* auth, const nsACString& scheme,
const nsACString& host, int32_t port, const nsACString& directory,
const nsACString& realm, const nsACString& challenge,
const nsHttpAuthIdentity& ident, const nsACString& creds,
nsIHttpAuthenticator* auth, const char* scheme, const char* host,
int32_t port, const char* directory, const char* realm,
const char* challenge, const nsHttpAuthIdentity& ident, const char* creds,
uint32_t generateFlags, nsISupports* sessionState, bool aProxyAuth) {
nsresult rv;
@ -419,8 +444,8 @@ nsresult nsHttpChannelAuthProvider::UpdateCache(
// if the credentials are not reusable, then we don't bother sticking
// them in the auth cache.
rv = authCache->SetAuthEntry(scheme, host, port, directory, realm,
saveCreds ? creds : ""_ns,
saveChallenge ? challenge : ""_ns, suffix,
saveCreds ? creds : nullptr,
saveChallenge ? challenge : nullptr, suffix,
saveIdentity ? &ident : nullptr, sessionState);
return rv;
}
@ -453,7 +478,7 @@ nsresult nsHttpChannelAuthProvider::PrepareForAuthentication(bool proxyAuth) {
nsresult rv;
nsCOMPtr<nsIHttpAuthenticator> precedingAuth;
nsCString proxyAuthType;
rv = GetAuthenticator(mProxyAuthType, proxyAuthType,
rv = GetAuthenticator(mProxyAuthType.get(), proxyAuthType,
getter_AddRefs(precedingAuth));
if (NS_FAILED(rv)) return rv;
@ -475,57 +500,13 @@ nsresult nsHttpChannelAuthProvider::PrepareForAuthentication(bool proxyAuth) {
return NS_OK;
}
nsresult nsHttpChannelAuthProvider::GetCredentials(
const nsACString& aChallenges, bool proxyAuth, nsCString& creds) {
using AuthChallenge = struct AuthChallenge {
nsDependentCSubstring challenge;
uint16_t algorithm = 0;
bool operator<(const struct AuthChallenge& aOther) const {
if (!algorithm) {
return false;
}
return algorithm > aOther.algorithm;
}
bool operator==(const struct AuthChallenge& aOther) const {
return algorithm == aOther.algorithm;
}
};
nsTArray<struct AuthChallenge> cc;
Tokenizer t(aChallenges);
nsDependentCSubstring line;
t.Record();
while (!t.CheckEOF()) {
Tokenizer::Token token1;
t.SkipUntil(Tokenizer::Token::NewLine());
t.Claim(line, Tokenizer::ClaimInclusion::INCLUDE_LAST);
if (!line.IsEmpty()) {
cc.AppendElement(AuthChallenge{line, 0});
}
t.SkipWhites(Tokenizer::WhiteSkipping::INCLUDE_NEW_LINE);
if (t.CheckEOF()) {
break;
}
t.Record();
}
for (auto& r : cc) {
nsAutoCString realm, domain, nonce, opaque;
bool stale;
uint16_t qop;
nsresult rv = nsHttpDigestAuth::ParseChallenge(
r.challenge, realm, domain, nonce, opaque, &stale, &r.algorithm, &qop);
if (NS_FAILED(rv)) {
continue;
}
}
cc.Sort();
nsresult nsHttpChannelAuthProvider::GetCredentials(const char* challenges,
bool proxyAuth,
nsCString& creds) {
nsCOMPtr<nsIHttpAuthenticator> auth;
nsAutoCString challenge;
nsCString authType; // force heap allocation to enable string sharing since
// we'll be assigning this value into mAuthType.
@ -546,8 +527,16 @@ nsresult nsHttpChannelAuthProvider::GetCredentials(
bool gotCreds = false;
// figure out which challenge we can handle and which authenticator to use.
for (size_t i = 0; i < cc.Length(); i++) {
rv = GetAuthenticator(cc[i].challenge, authType, getter_AddRefs(auth));
for (const char* eol = challenges - 1; eol;) {
const char* p = eol + 1;
// get the challenge string (LF separated -- see nsHttpHeaderArray)
if ((eol = strchr(p, '\n')) != nullptr)
challenge.Assign(p, eol - p);
else
challenge.Assign(p);
rv = GetAuthenticator(challenge.get(), authType, getter_AddRefs(auth));
if (NS_SUCCEEDED(rv)) {
//
// if we've already selected an auth type from a previous challenge
@ -571,8 +560,8 @@ nsresult nsHttpChannelAuthProvider::GetCredentials(
// if a particular auth method only knows 1 thing, like a
// non-identity based authentication method)
//
rv = GetCredentialsForChallenge(cc[i].challenge, authType, proxyAuth,
auth, creds);
rv = GetCredentialsForChallenge(challenge.get(), authType.get(),
proxyAuth, auth, creds);
if (NS_SUCCEEDED(rv)) {
gotCreds = true;
*currentAuthType = authType;
@ -584,15 +573,8 @@ nsresult nsHttpChannelAuthProvider::GetCredentials(
// expected asynchronously, save current challenge being
// processed and all remaining challenges to use later in
// OnAuthAvailable and now immediately return
mCurrentChallenge = cc[i].challenge;
// imperfect; does not save server-side preference ordering.
// instead, continues with remaining string as provided by client
mRemainingChallenges.Truncate();
while (i + 1 < cc.Length()) {
i++;
mRemainingChallenges.Append(cc[i].challenge);
mRemainingChallenges.Append("\n"_ns);
}
mCurrentChallenge = challenge;
mRemainingChallenges = eol ? eol + 1 : nullptr;
return rv;
}
@ -608,14 +590,14 @@ nsresult nsHttpChannelAuthProvider::GetCredentials(
currentAuthType->Truncate();
NS_IF_RELEASE(*currentContinuationState);
rv = GetCredentials(aChallenges, proxyAuth, creds);
rv = GetCredentials(challenges, proxyAuth, creds);
}
return rv;
}
nsresult nsHttpChannelAuthProvider::GetAuthorizationMembers(
bool proxyAuth, nsACString& scheme, nsCString& host, int32_t& port,
bool proxyAuth, nsACString& scheme, const char*& host, int32_t& port,
nsACString& path, nsHttpAuthIdentity*& ident,
nsISupports**& continuationState) {
if (proxyAuth) {
@ -647,10 +629,8 @@ nsresult nsHttpChannelAuthProvider::GetAuthorizationMembers(
}
nsresult nsHttpChannelAuthProvider::GetCredentialsForChallenge(
const nsACString& aChallenge, const nsACString& aAuthType, bool proxyAuth,
const char* challenge, const char* authType, bool proxyAuth,
nsIHttpAuthenticator* auth, nsCString& creds) {
const nsCString& flatChallenge = PromiseFlatCString(aChallenge);
const char* challenge = flatChallenge.get();
LOG(
("nsHttpChannelAuthProvider::GetCredentialsForChallenge "
"[this=%p channel=%p proxyAuth=%d challenges=%s]\n",
@ -664,7 +644,7 @@ nsresult nsHttpChannelAuthProvider::GetCredentialsForChallenge(
if (NS_FAILED(rv)) return rv;
nsAutoCString realm;
ParseRealm(aChallenge, realm);
ParseRealm(challenge, realm);
// if no realm, then use the auth type as the realm. ToUpperCase so the
// ficticious realm stands out a bit more.
@ -680,7 +660,7 @@ nsresult nsHttpChannelAuthProvider::GetCredentialsForChallenge(
// set informations that depend on whether
// we're authenticating against a proxy
// or a webserver
nsAutoCString host;
const char* host;
int32_t port;
nsHttpAuthIdentity* ident;
nsAutoCString path, scheme;
@ -728,8 +708,8 @@ nsresult nsHttpChannelAuthProvider::GetCredentialsForChallenge(
// try instead.
//
nsHttpAuthEntry* entry = nullptr;
Unused << authCache->GetAuthEntryForDomain(scheme, host, port, realm, suffix,
&entry);
Unused << authCache->GetAuthEntryForDomain(scheme.get(), host, port,
realm.get(), suffix, &entry);
// hold reference to the auth session state (in case we clear our
// reference to the entry).
@ -744,9 +724,9 @@ nsresult nsHttpChannelAuthProvider::GetCredentialsForChallenge(
// for digest auth, maybe our cached nonce value simply timed out...
bool identityInvalid;
nsISupports* sessionState = sessionStateGrip;
rv = auth->ChallengeReceived(mAuthChannel, aChallenge, proxyAuth,
&sessionState, &*continuationState,
&identityInvalid);
rv =
auth->ChallengeReceived(mAuthChannel, challenge, proxyAuth, &sessionState,
&*continuationState, &identityInvalid);
sessionStateGrip.swap(sessionState);
if (NS_FAILED(rv)) return rv;
@ -790,12 +770,13 @@ nsresult nsHttpChannelAuthProvider::GetCredentialsForChallenge(
LOG((" clearing bad auth cache entry\n"));
// ok, we've already tried this user identity, so clear the
// corresponding entry from the auth cache.
authCache->ClearAuthEntry(scheme, host, port, realm, suffix);
authCache->ClearAuthEntry(scheme.get(), host, port, realm.get(),
suffix);
entry = nullptr;
ident->Clear();
}
} else if (!identFromURI ||
(ident->User() == entry->Identity().User() &&
(nsCRT::strcmp(ident->User(), entry->Identity().User()) == 0 &&
!(loadFlags & (nsIChannel::LOAD_ANONYMOUS |
nsIChannel::LOAD_EXPLICIT_CREDENTIALS)))) {
LOG((" taking identity from auth cache\n"));
@ -805,12 +786,13 @@ nsresult nsHttpChannelAuthProvider::GetCredentialsForChallenge(
// to distinguish logons based on the supplied password alone,
// but that would be quite unusual... and i don't think we need
// to worry about such unorthodox cases.
*ident = entry->Identity();
rv = ident->Set(entry->Identity());
MOZ_ASSERT(NS_SUCCEEDED(rv));
identFromURI = false;
if (entry->Creds()[0] != '\0') {
LOG((" using cached credentials!\n"));
creds.Assign(entry->Creds());
return entry->AddPath(path);
return entry->AddPath(path.get());
}
}
} else if (!identFromURI) {
@ -821,31 +803,27 @@ nsresult nsHttpChannelAuthProvider::GetCredentialsForChallenge(
if (!entry && ident->IsEmpty()) {
uint32_t level = nsIAuthPrompt2::LEVEL_NONE;
if ((!proxyAuth && mUsingSSL) || (proxyAuth && mProxyUsingSSL)) {
if ((!proxyAuth && mUsingSSL) || (proxyAuth && mProxyUsingSSL))
level = nsIAuthPrompt2::LEVEL_SECURE;
} else if (authFlags & nsIHttpAuthenticator::IDENTITY_ENCRYPTED) {
else if (authFlags & nsIHttpAuthenticator::IDENTITY_ENCRYPTED)
level = nsIAuthPrompt2::LEVEL_PW_ENCRYPTED;
}
// Collect statistics on how frequently the various types of HTTP
// authentication are used over SSL and non-SSL connections.
if (Telemetry::CanRecordPrereleaseData()) {
if ("basic"_ns.Equals(aAuthType, nsCaseInsensitiveCStringComparator)) {
if ("basic"_ns.LowerCaseEqualsASCII(authType)) {
Telemetry::Accumulate(
Telemetry::HTTP_AUTH_TYPE_STATS,
UsingSSL() ? HTTP_AUTH_BASIC_SECURE : HTTP_AUTH_BASIC_INSECURE);
} else if ("digest"_ns.Equals(aAuthType,
nsCaseInsensitiveCStringComparator)) {
} else if ("digest"_ns.LowerCaseEqualsASCII(authType)) {
Telemetry::Accumulate(
Telemetry::HTTP_AUTH_TYPE_STATS,
UsingSSL() ? HTTP_AUTH_DIGEST_SECURE : HTTP_AUTH_DIGEST_INSECURE);
} else if ("ntlm"_ns.Equals(aAuthType,
nsCaseInsensitiveCStringComparator)) {
} else if ("ntlm"_ns.LowerCaseEqualsASCII(authType)) {
Telemetry::Accumulate(
Telemetry::HTTP_AUTH_TYPE_STATS,
UsingSSL() ? HTTP_AUTH_NTLM_SECURE : HTTP_AUTH_NTLM_INSECURE);
} else if ("negotiate"_ns.Equals(aAuthType,
nsCaseInsensitiveCStringComparator)) {
} else if ("negotiate"_ns.LowerCaseEqualsASCII(authType)) {
Telemetry::Accumulate(Telemetry::HTTP_AUTH_TYPE_STATS,
UsingSSL() ? HTTP_AUTH_NEGOTIATE_SECURE
: HTTP_AUTH_NEGOTIATE_INSECURE);
@ -872,7 +850,7 @@ nsresult nsHttpChannelAuthProvider::GetCredentialsForChallenge(
// at this point we are forced to interact with the user to get
// their username and password for this domain.
rv = PromptForIdentity(level, proxyAuth, realm, aAuthType, authFlags,
rv = PromptForIdentity(level, proxyAuth, realm.get(), authType, authFlags,
*ident);
if (NS_FAILED(rv)) return rv;
identFromURI = false;
@ -906,8 +884,10 @@ nsresult nsHttpChannelAuthProvider::GetCredentialsForChallenge(
// expecting to authenticate as.
//
nsCString result;
rv = GenCredsAndSetEntry(auth, proxyAuth, scheme, host, port, path, realm,
aChallenge, *ident, sessionStateGrip, creds);
rv = GenCredsAndSetEntry(auth, proxyAuth, scheme.get(), host, port,
path.get(), realm.get(), challenge, *ident,
sessionStateGrip, getter_Copies(result));
if (NS_SUCCEEDED(rv)) creds = result;
return rv;
}
@ -1032,20 +1012,25 @@ bool nsHttpChannelAuthProvider::BlockPrompt(bool proxyAuth) {
return false;
}
inline void GetAuthType(const nsACString& aChallenge, nsCString& authType) {
auto spaceIndex = aChallenge.FindChar(' ');
authType = Substring(aChallenge, 0, spaceIndex);
// normalize to lowercase
ToLowerCase(authType);
inline void GetAuthType(const char* challenge, nsCString& authType) {
const char* p;
// get the challenge type
if ((p = strchr(challenge, ' ')) != nullptr)
authType.Assign(challenge, p - challenge);
else
authType.Assign(challenge);
}
nsresult nsHttpChannelAuthProvider::GetAuthenticator(
const nsACString& aChallenge, nsCString& authType,
nsIHttpAuthenticator** auth) {
const char* challenge, nsCString& authType, nsIHttpAuthenticator** auth) {
LOG(("nsHttpChannelAuthProvider::GetAuthenticator [this=%p channel=%p]\n",
this, mAuthChannel));
GetAuthType(aChallenge, authType);
GetAuthType(challenge, authType);
// normalize to lowercase
ToLowerCase(authType);
nsCOMPtr<nsIHttpAuthenticator> authenticator;
if (authType.EqualsLiteral("negotiate")) {
@ -1066,16 +1051,6 @@ nsresult nsHttpChannelAuthProvider::GetAuthenticator(
return NS_OK;
}
// buf contains "domain\user"
static void ParseUserDomain(const nsAString& buf, nsDependentSubstring& user,
nsDependentSubstring& domain) {
auto backslashPos = buf.FindChar(u'\\');
if (backslashPos != kNotFound) {
domain.Rebind(buf, 0, backslashPos);
user.Rebind(buf, backslashPos + 1);
}
}
void nsHttpChannelAuthProvider::GetIdentityFromURI(uint32_t authFlags,
nsHttpAuthIdentity& ident) {
LOG(("nsHttpChannelAuthProvider::GetIdentityFromURI [this=%p channel=%p]\n",
@ -1098,18 +1073,13 @@ void nsHttpChannelAuthProvider::GetIdentityFromURI(uint32_t authFlags,
}
if (!userBuf.IsEmpty()) {
nsDependentSubstring user(userBuf, 0);
nsDependentSubstring domain(u""_ns, 0);
if (authFlags & nsIHttpAuthenticator::IDENTITY_INCLUDES_DOMAIN) {
ParseUserDomain(userBuf, user, domain);
}
ident = nsHttpAuthIdentity(domain, user, passBuf);
SetIdent(ident, authFlags, (char16_t*)userBuf.get(),
(char16_t*)passBuf.get());
}
}
static void OldParseRealm(const nsACString& aChallenge, nsACString& realm) {
void nsHttpChannelAuthProvider::ParseRealm(const char* challenge,
nsACString& realm) {
//
// From RFC2617 section 1.2, the realm value is defined as such:
//
@ -1120,9 +1090,6 @@ static void OldParseRealm(const nsACString& aChallenge, nsACString& realm) {
// end-of-line, if the string is not quoted.
//
const nsCString& flat = PromiseFlatCString(aChallenge);
const char* challenge = flat.get();
const char* p = nsCRT::strcasestr(challenge, "realm=");
if (p) {
bool has_quote = false;
@ -1139,10 +1106,9 @@ static void OldParseRealm(const nsACString& aChallenge, nsACString& realm) {
if (*end == '\\') {
// escaped character, store that one instead if not zero
if (!*++end) break;
} else if (*end == '\"') {
} else if (*end == '\"')
// end of string
break;
}
realm.Append(*end);
++end;
@ -1150,107 +1116,10 @@ static void OldParseRealm(const nsACString& aChallenge, nsACString& realm) {
} else {
// realm given without quotes
end = strchr(p, ' ');
if (end) {
if (end)
realm.Assign(p, end - p);
} else {
else
realm.Assign(p);
}
}
}
}
void nsHttpChannelAuthProvider::ParseRealm(const nsACString& aChallenge,
nsACString& realm) {
//
// From RFC2617 section 1.2, the realm value is defined as such:
//
// realm = "realm" "=" realm-value
// realm-value = quoted-string
//
// but, we'll accept anything after the the "=" up to the first space, or
// end-of-line, if the string is not quoted.
//
if (!StaticPrefs::network_auth_use_new_parse_realm()) {
OldParseRealm(aChallenge, realm);
return;
}
Tokenizer t(aChallenge);
// The challenge begins with the authType.
// If we can't find that something has probably gone wrong.
t.SkipWhites();
nsDependentCSubstring authType;
if (!t.ReadWord(authType)) {
return;
}
// Will return true if the tokenizer advanced the cursor - false otherwise.
auto readParam = [&](nsDependentCSubstring& key, nsAutoCString& value) {
key.Rebind(EmptyCString(), 0);
value.Truncate();
t.SkipWhites();
if (!t.ReadWord(key)) {
return false;
}
t.SkipWhites();
if (!t.CheckChar('=')) {
return true;
}
t.SkipWhites();
Tokenizer::Token token1;
t.Record();
if (!t.Next(token1)) {
return true;
}
nsDependentCSubstring sub;
bool hasQuote = false;
if (token1.Equals(Tokenizer::Token::Char('"'))) {
hasQuote = true;
} else {
t.Claim(sub, Tokenizer::ClaimInclusion::INCLUDE_LAST);
value.Append(sub);
}
t.Record();
Tokenizer::Token token2;
while (t.Next(token2)) {
if (hasQuote && token2.Equals(Tokenizer::Token::Char('"')) &&
!token1.Equals(Tokenizer::Token::Char('\\'))) {
break;
}
if (!hasQuote && (token2.Type() == Tokenizer::TokenType::TOKEN_WS ||
token2.Type() == Tokenizer::TokenType::TOKEN_EOL)) {
break;
}
t.Claim(sub, Tokenizer::ClaimInclusion::INCLUDE_LAST);
if (!sub.Equals(R"(\)")) {
value.Append(sub);
}
t.Record();
token1 = token2;
}
return true;
};
while (!t.CheckEOF()) {
nsDependentCSubstring key;
nsAutoCString value;
// If we couldn't read anything, and the input isn't followed by a ,
// then we exit.
if (!readParam(key, value) && !t.Check(Tokenizer::Token::Char(','))) {
break;
}
// When we find the first instance of realm we exit.
// Theoretically there should be only one instance and we should fail
// if there are more, but we're trying to preserve existing behaviour.
if (key.Equals("realm"_ns, nsCaseInsensitiveCStringComparator)) {
realm = value;
break;
}
}
}
@ -1258,7 +1127,7 @@ void nsHttpChannelAuthProvider::ParseRealm(const nsACString& aChallenge,
class nsHTTPAuthInformation : public nsAuthInformationHolder {
public:
nsHTTPAuthInformation(uint32_t aFlags, const nsString& aRealm,
const nsACString& aAuthType)
const nsCString& aAuthType)
: nsAuthInformationHolder(aFlags, aRealm, aAuthType) {}
void SetToHttpAuthIdentity(uint32_t authFlags, nsHttpAuthIdentity& identity);
@ -1266,12 +1135,14 @@ class nsHTTPAuthInformation : public nsAuthInformationHolder {
void nsHTTPAuthInformation::SetToHttpAuthIdentity(
uint32_t authFlags, nsHttpAuthIdentity& identity) {
identity = nsHttpAuthIdentity(Domain(), User(), Password());
DebugOnly<nsresult> rv =
identity.Set(Domain().get(), User().get(), Password().get());
MOZ_ASSERT(NS_SUCCEEDED(rv));
}
nsresult nsHttpChannelAuthProvider::PromptForIdentity(
uint32_t level, bool proxyAuth, const nsACString& realm,
const nsACString& authType, uint32_t authFlags, nsHttpAuthIdentity& ident) {
uint32_t level, bool proxyAuth, const char* realm, const char* authType,
uint32_t authFlags, nsHttpAuthIdentity& ident) {
LOG(("nsHttpChannelAuthProvider::PromptForIdentity [this=%p channel=%p]\n",
this, mAuthChannel));
@ -1309,16 +1180,15 @@ nsresult nsHttpChannelAuthProvider::PromptForIdentity(
mTriedHostAuth = true;
}
if (authFlags & nsIHttpAuthenticator::IDENTITY_INCLUDES_DOMAIN) {
if (authFlags & nsIHttpAuthenticator::IDENTITY_INCLUDES_DOMAIN)
promptFlags |= nsIAuthInformation::NEED_DOMAIN;
}
if (mCrossOrigin) {
promptFlags |= nsIAuthInformation::CROSS_ORIGIN_SUB_RESOURCE;
}
RefPtr<nsHTTPAuthInformation> holder =
new nsHTTPAuthInformation(promptFlags, realmU, authType);
RefPtr<nsHTTPAuthInformation> holder = new nsHTTPAuthInformation(
promptFlags, realmU, nsDependentCString(authType));
if (!holder) return NS_ERROR_OUT_OF_MEMORY;
nsCOMPtr<nsIChannel> channel(do_QueryInterface(mAuthChannel, &rv));
@ -1337,11 +1207,10 @@ nsresult nsHttpChannelAuthProvider::PromptForIdentity(
rv = authPrompt->PromptAuth(channel, level, holder, &retval);
if (NS_FAILED(rv)) return rv;
if (!retval) {
if (!retval)
rv = NS_ERROR_ABORT;
} else {
else
holder->SetToHttpAuthIdentity(authFlags, ident);
}
}
// remember that we successfully showed the user an auth dialog
@ -1373,7 +1242,7 @@ NS_IMETHODIMP nsHttpChannelAuthProvider::OnAuthAvailable(
nsresult rv;
nsAutoCString host;
const char* host;
int32_t port;
nsHttpAuthIdentity* ident;
nsAutoCString path, scheme;
@ -1383,7 +1252,7 @@ NS_IMETHODIMP nsHttpChannelAuthProvider::OnAuthAvailable(
if (NS_FAILED(rv)) OnAuthCancelled(aContext, false);
nsAutoCString realm;
ParseRealm(mCurrentChallenge, realm);
ParseRealm(mCurrentChallenge.get(), realm);
nsCOMPtr<nsIChannel> chan = do_QueryInterface(mAuthChannel);
nsAutoCString suffix;
@ -1394,20 +1263,21 @@ NS_IMETHODIMP nsHttpChannelAuthProvider::OnAuthAvailable(
nsHttpAuthCache* authCache = gHttpHandler->AuthCache(mIsPrivate);
nsHttpAuthEntry* entry = nullptr;
Unused << authCache->GetAuthEntryForDomain(scheme, host, port, realm, suffix,
&entry);
Unused << authCache->GetAuthEntryForDomain(scheme.get(), host, port,
realm.get(), suffix, &entry);
nsCOMPtr<nsISupports> sessionStateGrip;
if (entry) sessionStateGrip = entry->mMetaData;
nsAuthInformationHolder* holder =
static_cast<nsAuthInformationHolder*>(aAuthInfo);
*ident =
nsHttpAuthIdentity(holder->Domain(), holder->User(), holder->Password());
rv = ident->Set(holder->Domain().get(), holder->User().get(),
holder->Password().get());
MOZ_ASSERT(NS_SUCCEEDED(rv));
nsAutoCString unused;
nsCOMPtr<nsIHttpAuthenticator> auth;
rv = GetAuthenticator(mCurrentChallenge, unused, getter_AddRefs(auth));
rv = GetAuthenticator(mCurrentChallenge.get(), unused, getter_AddRefs(auth));
if (NS_FAILED(rv)) {
MOZ_ASSERT(false, "GetAuthenticator failed");
OnAuthCancelled(aContext, true);
@ -1415,8 +1285,9 @@ NS_IMETHODIMP nsHttpChannelAuthProvider::OnAuthAvailable(
}
nsCString creds;
rv = GenCredsAndSetEntry(auth, mProxyAuth, scheme, host, port, path, realm,
mCurrentChallenge, *ident, sessionStateGrip, creds);
rv = GenCredsAndSetEntry(auth, mProxyAuth, scheme.get(), host, port,
path.get(), realm.get(), mCurrentChallenge.get(),
*ident, sessionStateGrip, getter_Copies(creds));
mCurrentChallenge.Truncate();
if (NS_FAILED(rv)) {
@ -1469,7 +1340,7 @@ NS_IMETHODIMP nsHttpChannelAuthProvider::OnAuthCancelled(nsISupports* aContext,
NS_IF_RELEASE(mAuthContinuationState);
}
nsAutoCString creds;
rv = GetCredentials(mRemainingChallenges, mProxyAuth, creds);
rv = GetCredentials(mRemainingChallenges.get(), mProxyAuth, creds);
if (NS_SUCCEEDED(rv)) {
// GetCredentials loaded the credentials from the cache or
// some other way in a synchronous manner, process those
@ -1497,7 +1368,7 @@ NS_IMETHODIMP nsHttpChannelAuthProvider::OnAuthCancelled(nsISupports* aContext,
}
NS_IMETHODIMP nsHttpChannelAuthProvider::OnCredsGenerated(
const nsACString& aGeneratedCreds, uint32_t aFlags, nsresult aResult,
const char* aGeneratedCreds, uint32_t aFlags, nsresult aResult,
nsISupports* aSessionState, nsISupports* aContinuationState) {
nsresult rv;
@ -1525,10 +1396,10 @@ NS_IMETHODIMP nsHttpChannelAuthProvider::OnCredsGenerated(
nsCOMPtr<nsIHttpAuthenticator> auth;
nsAutoCString unused;
rv = GetAuthenticator(mCurrentChallenge, unused, getter_AddRefs(auth));
rv = GetAuthenticator(mCurrentChallenge.get(), unused, getter_AddRefs(auth));
NS_ENSURE_SUCCESS(rv, rv);
nsAutoCString host;
const char* host;
int32_t port;
nsHttpAuthIdentity* ident;
nsAutoCString directory, scheme;
@ -1536,19 +1407,19 @@ NS_IMETHODIMP nsHttpChannelAuthProvider::OnCredsGenerated(
// Get realm from challenge
nsAutoCString realm;
ParseRealm(mCurrentChallenge, realm);
ParseRealm(mCurrentChallenge.get(), realm);
rv = GetAuthorizationMembers(mProxyAuth, scheme, host, port, directory, ident,
unusedContinuationState);
if (NS_FAILED(rv)) return rv;
rv =
UpdateCache(auth, scheme, host, port, directory, realm, mCurrentChallenge,
*ident, aGeneratedCreds, aFlags, aSessionState, mProxyAuth);
rv = UpdateCache(auth, scheme.get(), host, port, directory.get(), realm.get(),
mCurrentChallenge.get(), *ident, aGeneratedCreds, aFlags,
aSessionState, mProxyAuth);
MOZ_ASSERT(NS_SUCCEEDED(rv));
mCurrentChallenge.Truncate();
rv = ContinueOnAuthAvailable(aGeneratedCreds);
rv = ContinueOnAuthAvailable(nsDependentCString(aGeneratedCreds));
MOZ_ASSERT(NS_SUCCEEDED(rv));
return NS_OK;
}
@ -1556,11 +1427,10 @@ NS_IMETHODIMP nsHttpChannelAuthProvider::OnCredsGenerated(
nsresult nsHttpChannelAuthProvider::ContinueOnAuthAvailable(
const nsACString& creds) {
nsresult rv;
if (mProxyAuth) {
if (mProxyAuth)
rv = mAuthChannel->SetProxyCredentials(creds);
} else {
else
rv = mAuthChannel->SetWWWCredentials(creds);
}
if (NS_FAILED(rv)) return rv;
// drop our remaining list of challenges. We don't need them, because we
@ -1591,16 +1461,14 @@ bool nsHttpChannelAuthProvider::ConfirmAuth(const char* bundleKey,
if (NS_FAILED(rv)) return true;
if (mSuppressDefensiveAuth ||
!(loadFlags & nsIChannel::LOAD_INITIAL_DOCUMENT_URI)) {
!(loadFlags & nsIChannel::LOAD_INITIAL_DOCUMENT_URI))
return true;
}
nsAutoCString userPass;
rv = mURI->GetUserPass(userPass);
if (NS_FAILED(rv) ||
(userPass.Length() < gHttpHandler->PhishyUserPassLength())) {
(userPass.Length() < gHttpHandler->PhishyUserPassLength()))
return true;
}
// we try to confirm by prompting the user. if we cannot do so, then
// assume the user said ok. this is done to keep things working in
@ -1707,8 +1575,8 @@ bool nsHttpChannelAuthProvider::ConfirmAuth(const char* bundleKey,
}
void nsHttpChannelAuthProvider::SetAuthorizationHeader(
nsHttpAuthCache* authCache, nsHttpAtom header, const nsACString& scheme,
const nsACString& host, int32_t port, const nsACString& path,
nsHttpAuthCache* authCache, nsHttpAtom header, const char* scheme,
const char* host, int32_t port, const char* path,
nsHttpAuthIdentity& ident) {
nsHttpAuthEntry* entry = nullptr;
nsresult rv;
@ -1756,7 +1624,7 @@ void nsHttpChannelAuthProvider::SetAuthorizationHeader(
// up the one from the auth cache instead.
// when this is undesired, specify LOAD_EXPLICIT_CREDENTIALS load
// flag.
if (ident.User() == entry->User()) {
if (nsCRT::strcmp(ident.User(), entry->User()) == 0) {
uint32_t loadFlags;
if (NS_SUCCEEDED(mAuthChannel->GetLoadFlags(&loadFlags)) &&
!(loadFlags & nsIChannel::LOAD_EXPLICIT_CREDENTIALS)) {
@ -1766,41 +1634,42 @@ void nsHttpChannelAuthProvider::SetAuthorizationHeader(
}
bool identFromURI;
if (ident.IsEmpty()) {
ident = entry->Identity();
rv = ident.Set(entry->Identity());
MOZ_ASSERT(NS_SUCCEEDED(rv));
identFromURI = false;
} else {
} else
identFromURI = true;
}
nsCString temp; // this must have the same lifetime as creds
nsAutoCString creds(entry->Creds());
const char* creds = entry->Creds();
const char* challenge = entry->Challenge();
// we can only send a preemptive Authorization header if we have either
// stored credentials or a stored challenge from which to derive
// credentials. if the identity is from the URI, then we cannot use
// the stored credentials.
if ((creds.IsEmpty() || identFromURI) && !entry->Challenge().IsEmpty()) {
if ((!creds[0] || identFromURI) && challenge[0]) {
nsCOMPtr<nsIHttpAuthenticator> auth;
nsAutoCString unused;
rv = GetAuthenticator(entry->Challenge(), unused, getter_AddRefs(auth));
rv = GetAuthenticator(challenge, unused, getter_AddRefs(auth));
if (NS_SUCCEEDED(rv)) {
bool proxyAuth = (header == nsHttp::Proxy_Authorization);
rv = GenCredsAndSetEntry(auth, proxyAuth, scheme, host, port, path,
entry->Realm(), entry->Challenge(), ident,
entry->mMetaData, temp);
if (NS_SUCCEEDED(rv)) creds = temp;
entry->Realm(), challenge, ident,
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(*continuationState);
}
}
if (!creds.IsEmpty()) {
if (creds[0]) {
LOG((" adding \"%s\" request header\n", header.get()));
if (header == nsHttp::Proxy_Authorization) {
rv = mAuthChannel->SetProxyCredentials(creds);
rv = mAuthChannel->SetProxyCredentials(nsDependentCString(creds));
MOZ_ASSERT(NS_SUCCEEDED(rv));
} else {
rv = mAuthChannel->SetWWWCredentials(creds);
rv = mAuthChannel->SetWWWCredentials(nsDependentCString(creds));
MOZ_ASSERT(NS_SUCCEEDED(rv));
}
@ -1809,20 +1678,18 @@ void nsHttpChannelAuthProvider::SetAuthorizationHeader(
// this for non-proxy auth since the URL's userpass is not used for
// proxy auth.
if (header == nsHttp::Authorization) mSuppressDefensiveAuth = true;
} else {
} else
ident.Clear(); // don't remember the identity
}
}
}
nsresult nsHttpChannelAuthProvider::GetCurrentPath(nsACString& path) {
nsresult rv;
nsCOMPtr<nsIURL> url = do_QueryInterface(mURI);
if (url) {
if (url)
rv = url->GetDirectory(path);
} else {
else
rv = mURI->GetPathQueryRef(path);
}
return rv;
}

Просмотреть файл

@ -42,13 +42,13 @@ class nsHttpChannelAuthProvider final : public nsIHttpChannelAuthProvider,
private:
virtual ~nsHttpChannelAuthProvider();
const nsCString& ProxyHost() const {
return mProxyInfo ? mProxyInfo->Host() : EmptyCString();
const char* ProxyHost() const {
return mProxyInfo ? mProxyInfo->Host().get() : nullptr;
}
int32_t ProxyPort() const { return mProxyInfo ? mProxyInfo->Port() : -1; }
const nsCString& Host() const { return mHost; }
const char* Host() const { return mHost.get(); }
int32_t Port() const { return mPort; }
bool UsingSSL() const { return mUsingSSL; }
@ -58,15 +58,14 @@ class nsHttpChannelAuthProvider final : public nsIHttpChannelAuthProvider,
[[nodiscard]] nsresult PrepareForAuthentication(bool proxyAuth);
[[nodiscard]] nsresult GenCredsAndSetEntry(
nsIHttpAuthenticator*, bool proxyAuth, const nsACString& scheme,
const nsACString& host, int32_t port, const nsACString& dir,
const nsACString& realm, const nsACString& challenge,
const nsHttpAuthIdentity& ident, nsCOMPtr<nsISupports>& session,
nsACString& result);
[[nodiscard]] nsresult GetAuthenticator(const nsACString& aChallenge,
nsCString& authType,
nsIHttpAuthenticator*, bool proxyAuth, const char* scheme,
const char* host, int32_t port, const char* dir, const char* realm,
const char* challenge, const nsHttpAuthIdentity& ident,
nsCOMPtr<nsISupports>& session, char** result);
[[nodiscard]] nsresult GetAuthenticator(const char* challenge,
nsCString& scheme,
nsIHttpAuthenticator** auth);
void ParseRealm(const nsACString&, nsACString& realm);
void ParseRealm(const char* challenge, nsACString& realm);
void GetIdentityFromURI(uint32_t authFlags, nsHttpAuthIdentity&);
/**
@ -75,21 +74,23 @@ class nsHttpChannelAuthProvider final : public nsIHttpChannelAuthProvider,
* the user's decision will be gathered in a callback and is not an actual
* error.
*/
[[nodiscard]] nsresult GetCredentials(const nsACString& challenges,
bool proxyAuth, nsCString& creds);
[[nodiscard]] nsresult GetCredentialsForChallenge(
const nsACString& aChallenge, const nsACString& aAuthType, bool proxyAuth,
nsIHttpAuthenticator* auth, nsCString& creds);
[[nodiscard]] nsresult GetCredentials(const char* challenges, bool proxyAuth,
nsCString& creds);
[[nodiscard]] nsresult GetCredentialsForChallenge(const char* challenge,
const char* scheme,
bool proxyAuth,
nsIHttpAuthenticator* auth,
nsCString& creds);
[[nodiscard]] nsresult PromptForIdentity(uint32_t level, bool proxyAuth,
const nsACString& realm,
const nsACString& authType,
const char* realm,
const char* authType,
uint32_t authFlags,
nsHttpAuthIdentity&);
bool ConfirmAuth(const char* bundleKey, bool doYesNoPrompt);
void SetAuthorizationHeader(nsHttpAuthCache*, nsHttpAtom header,
const nsACString& scheme, const nsACString& host,
int32_t port, const nsACString& path,
const char* scheme, const char* host,
int32_t port, const char* path,
nsHttpAuthIdentity& ident);
[[nodiscard]] nsresult GetCurrentPath(nsACString&);
/**
@ -98,7 +99,7 @@ class nsHttpChannelAuthProvider final : public nsIHttpChannelAuthProvider,
* with what authorization we work (WWW or proxy).
*/
[[nodiscard]] nsresult GetAuthorizationMembers(
bool proxyAuth, nsACString& scheme, nsCString& host, int32_t& port,
bool proxyAuth, nsACString& scheme, const char*& host, int32_t& port,
nsACString& path, nsHttpAuthIdentity*& ident,
nsISupports**& continuationState);
/**
@ -126,26 +127,26 @@ class nsHttpChannelAuthProvider final : public nsIHttpChannelAuthProvider,
// Store credentials to the cache when appropriate aFlags are set.
[[nodiscard]] nsresult UpdateCache(
nsIHttpAuthenticator* aAuth, const nsACString& aScheme,
const nsACString& aHost, int32_t aPort, const nsACString& aDirectory,
const nsACString& aRealm, const nsACString& aChallenge,
const nsHttpAuthIdentity& aIdent, const nsACString& aCreds,
uint32_t aGenerateFlags, nsISupports* aSessionState, bool aProxyAuth);
nsIHttpAuthenticator* aAuth, const char* aScheme, const char* aHost,
int32_t aPort, const char* aDirectory, const char* aRealm,
const char* aChallenge, const nsHttpAuthIdentity& aIdent,
const char* aCreds, uint32_t aGenerateFlags, nsISupports* aSessionState,
bool aProxyAuth);
private:
nsIHttpAuthenticableChannel* mAuthChannel{nullptr}; // weak ref
nsIHttpAuthenticableChannel* mAuthChannel; // weak ref
nsCOMPtr<nsIURI> mURI;
nsCOMPtr<nsProxyInfo> mProxyInfo;
nsCString mHost;
int32_t mPort{-1};
bool mUsingSSL{false};
bool mProxyUsingSSL{false};
bool mIsPrivate{false};
int32_t mPort;
bool mUsingSSL;
bool mProxyUsingSSL;
bool mIsPrivate;
nsISupports* mProxyAuthContinuationState{nullptr};
nsISupports* mProxyAuthContinuationState;
nsCString mProxyAuthType;
nsISupports* mAuthContinuationState{nullptr};
nsISupports* mAuthContinuationState;
nsCString mAuthType;
nsHttpAuthIdentity mIdent;
nsHttpAuthIdentity mProxyIdent;

Просмотреть файл

@ -23,13 +23,6 @@
#include "nsICryptoHash.h"
#include "nsComponentManagerUtils.h"
constexpr uint16_t DigestLength(uint16_t aAlgorithm) {
if (aAlgorithm & (ALGO_SHA256 | ALGO_SHA256_SESS)) {
return SHA256_DIGEST_LENGTH;
}
return MD5_DIGEST_LENGTH;
}
namespace mozilla {
namespace net {
@ -58,8 +51,7 @@ NS_IMPL_ISUPPORTS(nsHttpDigestAuth, nsIHttpAuthenticator)
// nsHttpDigestAuth <protected>
//-----------------------------------------------------------------------------
nsresult nsHttpDigestAuth::DigestHash(const char* buf, uint32_t len,
uint16_t algorithm) {
nsresult nsHttpDigestAuth::MD5Hash(const char* buf, uint32_t len) {
nsresult rv;
// Cache a reference to the nsICryptoHash instance since we'll be calling
@ -72,14 +64,7 @@ nsresult nsHttpDigestAuth::DigestHash(const char* buf, uint32_t len,
}
}
uint32_t dlen;
if (algorithm & (ALGO_SHA256 | ALGO_SHA256_SESS)) {
rv = mVerifier->Init(nsICryptoHash::SHA256);
dlen = SHA256_DIGEST_LENGTH;
} else {
rv = mVerifier->Init(nsICryptoHash::MD5);
dlen = MD5_DIGEST_LENGTH;
}
rv = mVerifier->Init(nsICryptoHash::MD5);
if (NS_FAILED(rv)) return rv;
rv = mVerifier->Update((unsigned char*)buf, len);
@ -89,7 +74,7 @@ nsresult nsHttpDigestAuth::DigestHash(const char* buf, uint32_t len,
rv = mVerifier->Finish(false, hashString);
if (NS_FAILED(rv)) return rv;
NS_ENSURE_STATE(hashString.Length() == dlen);
NS_ENSURE_STATE(hashString.Length() == sizeof(mHashBuf));
memcpy(mHashBuf, hashString.get(), hashString.Length());
return rv;
@ -154,8 +139,7 @@ nsresult nsHttpDigestAuth::GetMethodAndPath(
NS_IMETHODIMP
nsHttpDigestAuth::ChallengeReceived(nsIHttpAuthenticableChannel* authChannel,
const nsACString& challenge,
bool isProxyAuth,
const char* challenge, bool isProxyAuth,
nsISupports** sessionState,
nsISupports** continuationState,
bool* result) {
@ -165,14 +149,6 @@ nsHttpDigestAuth::ChallengeReceived(nsIHttpAuthenticableChannel* authChannel,
nsresult rv = ParseChallenge(challenge, realm, domain, nonce, opaque, &stale,
&algorithm, &qop);
if (!(algorithm &
(ALGO_MD5 | ALGO_MD5_SESS | ALGO_SHA256 | ALGO_SHA256_SESS))) {
// they asked for an algorithm that we do not support yet (like SHA-512/256)
NS_WARNING("unsupported algorithm requested by Digest authentication");
return NS_ERROR_NOT_IMPLEMENTED;
}
if (NS_FAILED(rv)) return rv;
// if the challenge has the "stale" flag set, then the user identity is not
@ -188,28 +164,28 @@ nsHttpDigestAuth::ChallengeReceived(nsIHttpAuthenticableChannel* authChannel,
NS_IMETHODIMP
nsHttpDigestAuth::GenerateCredentialsAsync(
nsIHttpAuthenticableChannel* authChannel,
nsIHttpAuthenticatorCallback* aCallback, const nsACString& challenge,
bool isProxyAuth, const nsAString& domain, const nsAString& username,
const nsAString& password, nsISupports* sessionState,
nsIHttpAuthenticatorCallback* aCallback, const char* challenge,
bool isProxyAuth, const char16_t* domain, const char16_t* username,
const char16_t* password, nsISupports* sessionState,
nsISupports* continuationState, nsICancelable** aCancellable) {
return NS_ERROR_NOT_IMPLEMENTED;
}
NS_IMETHODIMP
nsHttpDigestAuth::GenerateCredentials(
nsIHttpAuthenticableChannel* authChannel, const nsACString& aChallenge,
bool isProxyAuth, const nsAString& userdomain, const nsAString& username,
const nsAString& password, nsISupports** sessionState,
nsISupports** continuationState, uint32_t* aFlags, nsACString& creds)
nsIHttpAuthenticableChannel* authChannel, const char* challenge,
bool isProxyAuth, const char16_t* userdomain, const char16_t* username,
const char16_t* password, nsISupports** sessionState,
nsISupports** continuationState, uint32_t* aFlags, char** creds)
{
LOG(("nsHttpDigestAuth::GenerateCredentials [challenge=%s]\n",
aChallenge.BeginReading()));
LOG(("nsHttpDigestAuth::GenerateCredentials [challenge=%s]\n", challenge));
NS_ENSURE_ARG_POINTER(creds);
*aFlags = 0;
bool isDigestAuth = StringBeginsWith(aChallenge, "digest "_ns,
nsCaseInsensitiveCStringComparator);
bool isDigestAuth = !nsCRT::strncasecmp(challenge, "digest ", 7);
NS_ENSURE_TRUE(isDigestAuth, NS_ERROR_UNEXPECTED);
// IIS implementation requires extra quotes
@ -233,7 +209,7 @@ nsHttpDigestAuth::GenerateCredentials(
bool stale;
uint16_t algorithm, qop;
rv = ParseChallenge(aChallenge, realm, domain, nonce, opaque, &stale,
rv = ParseChallenge(challenge, realm, domain, nonce, opaque, &stale,
&algorithm, &qop);
if (NS_FAILED(rv)) {
LOG(
@ -243,11 +219,10 @@ nsHttpDigestAuth::GenerateCredentials(
return rv;
}
const uint32_t dhexlen = 2 * DigestLength(algorithm) + 1;
char ha1_digest[dhexlen];
char ha2_digest[dhexlen];
char response_digest[dhexlen];
char upload_data_digest[dhexlen];
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
@ -283,8 +258,7 @@ nsHttpDigestAuth::GenerateCredentials(
#endif
}
if (!(algorithm &
(ALGO_MD5 | ALGO_MD5_SESS | ALGO_SHA256 | ALGO_SHA256_SESS))) {
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;
@ -335,12 +309,11 @@ nsHttpDigestAuth::GenerateCredentials(
rv = CalculateHA1(cUser, cPass, realm, algorithm, nonce, cnonce, ha1_digest);
if (NS_FAILED(rv)) return rv;
rv = CalculateHA2(httpMethod, path, algorithm, qop, upload_data_digest,
ha2_digest);
rv = CalculateHA2(httpMethod, path, qop, upload_data_digest, ha2_digest);
if (NS_FAILED(rv)) return rv;
rv = CalculateResponse(ha1_digest, ha2_digest, algorithm, nonce, qop,
nonce_count, cnonce, response_digest);
rv = CalculateResponse(ha1_digest, ha2_digest, nonce, qop, nonce_count,
cnonce, response_digest);
if (NS_FAILED(rv)) return rv;
//
@ -371,15 +344,10 @@ nsHttpDigestAuth::GenerateCredentials(
authString += path;
if (algorithm & ALGO_SPECIFIED) {
authString.AppendLiteral("\", algorithm=");
if (algorithm & ALGO_MD5_SESS) {
if (algorithm & ALGO_MD5_SESS)
authString.AppendLiteral("MD5-sess");
} else if (algorithm & ALGO_SHA256) {
authString.AppendLiteral("SHA-256");
} else if (algorithm & ALGO_SHA256_SESS) {
authString.AppendLiteral("SHA-256-sess");
} else {
else
authString.AppendLiteral("MD5");
}
} else {
authString += '\"';
}
@ -407,7 +375,7 @@ nsHttpDigestAuth::GenerateCredentials(
NS_ENSURE_SUCCESS(rv, rv);
}
creds = authString;
*creds = ToNewCString(authString);
return NS_OK;
}
@ -422,25 +390,23 @@ nsHttpDigestAuth::GetAuthFlags(uint32_t* flags) {
}
nsresult nsHttpDigestAuth::CalculateResponse(
const char* ha1_digest, const char* ha2_digest, uint16_t algorithm,
const nsCString& nonce, uint16_t qop, const char* nonce_count,
const nsCString& cnonce, char* result) {
const uint32_t dhexlen = 2 * DigestLength(algorithm);
uint32_t len = 2 * dhexlen + nonce.Length() + 2;
const char* ha1_digest, const char* ha2_digest, const nsCString& nonce,
uint16_t qop, const char* nonce_count, const nsCString& cnonce,
char* result) {
uint32_t 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) {
if (qop & QOP_AUTH_INT)
len += 8; // length of "auth-int"
} else {
else
len += 4; // length of "auth"
}
}
nsAutoCString contents;
contents.SetCapacity(len);
contents.Append(ha1_digest, dhexlen);
contents.Append(ha1_digest, EXPANDED_DIGEST_LENGTH);
contents.Append(':');
contents.Append(nonce);
contents.Append(':');
@ -450,42 +416,37 @@ nsresult nsHttpDigestAuth::CalculateResponse(
contents.Append(':');
contents.Append(cnonce);
contents.Append(':');
if (qop & QOP_AUTH_INT) {
if (qop & QOP_AUTH_INT)
contents.AppendLiteral("auth-int:");
} else {
else
contents.AppendLiteral("auth:");
}
}
contents.Append(ha2_digest, dhexlen);
contents.Append(ha2_digest, EXPANDED_DIGEST_LENGTH);
nsresult rv = DigestHash(contents.get(), contents.Length(), algorithm);
if (NS_SUCCEEDED(rv)) rv = ExpandToHex(mHashBuf, result, algorithm);
nsresult rv = MD5Hash(contents.get(), contents.Length());
if (NS_SUCCEEDED(rv)) rv = ExpandToHex(mHashBuf, result);
return rv;
}
nsresult nsHttpDigestAuth::ExpandToHex(const char* digest, char* result,
uint16_t algorithm) {
nsresult nsHttpDigestAuth::ExpandToHex(const char* digest, char* result) {
int16_t index, value;
const int16_t dlen = DigestLength(algorithm);
for (index = 0; index < dlen; index++) {
for (index = 0; index < DIGEST_LENGTH; index++) {
value = (digest[index] >> 4) & 0xf;
if (value < 10) {
if (value < 10)
result[index * 2] = value + '0';
} else {
else
result[index * 2] = value - 10 + 'a';
}
value = digest[index] & 0xf;
if (value < 10) {
if (value < 10)
result[(index * 2) + 1] = value + '0';
} else {
else
result[(index * 2) + 1] = value - 10 + 'a';
}
}
result[2 * dlen] = 0;
result[EXPANDED_DIGEST_LENGTH] = 0;
return NS_OK;
}
@ -495,10 +456,10 @@ nsresult nsHttpDigestAuth::CalculateHA1(const nsCString& username,
uint16_t algorithm,
const nsCString& nonce,
const nsCString& cnonce, char* result) {
const int16_t dhexlen = 2 * DigestLength(algorithm);
int16_t len = username.Length() + password.Length() + realm.Length() + 2;
if (algorithm & (ALGO_MD5_SESS | ALGO_SHA256_SESS)) {
int16_t exlen = dhexlen + nonce.Length() + cnonce.Length() + 2;
if (algorithm & ALGO_MD5_SESS) {
int16_t exlen =
EXPANDED_DIGEST_LENGTH + nonce.Length() + cnonce.Length() + 2;
if (exlen > len) len = exlen;
}
@ -512,38 +473,36 @@ nsresult nsHttpDigestAuth::CalculateHA1(const nsCString& username,
contents.Append(password);
nsresult rv;
rv = DigestHash(contents.get(), contents.Length(), algorithm);
rv = MD5Hash(contents.get(), contents.Length());
if (NS_FAILED(rv)) return rv;
if (algorithm & (ALGO_MD5_SESS | ALGO_SHA256_SESS)) {
char part1[dhexlen + 1];
rv = ExpandToHex(mHashBuf, part1, algorithm);
if (algorithm & ALGO_MD5_SESS) {
char part1[EXPANDED_DIGEST_LENGTH + 1];
rv = ExpandToHex(mHashBuf, part1);
MOZ_ASSERT(NS_SUCCEEDED(rv));
contents.Assign(part1, dhexlen);
contents.Assign(part1, EXPANDED_DIGEST_LENGTH);
contents.Append(':');
contents.Append(nonce);
contents.Append(':');
contents.Append(cnonce);
rv = DigestHash(contents.get(), contents.Length(), algorithm);
rv = MD5Hash(contents.get(), contents.Length());
if (NS_FAILED(rv)) return rv;
}
return ExpandToHex(mHashBuf, result, algorithm);
return ExpandToHex(mHashBuf, result);
}
nsresult nsHttpDigestAuth::CalculateHA2(const nsCString& method,
const nsCString& path,
uint16_t algorithm, uint16_t qop,
const nsCString& path, uint16_t qop,
const char* bodyDigest, char* result) {
uint16_t methodLen = method.Length();
uint32_t pathLen = path.Length();
uint32_t len = methodLen + pathLen + 1;
const uint32_t dhexlen = 2 * DigestLength(algorithm);
if (qop & QOP_AUTH_INT) {
len += dhexlen + 1;
len += EXPANDED_DIGEST_LENGTH + 1;
}
nsAutoCString contents;
@ -555,62 +514,43 @@ nsresult nsHttpDigestAuth::CalculateHA2(const nsCString& method,
if (qop & QOP_AUTH_INT) {
contents.Append(':');
contents.Append(bodyDigest, dhexlen);
contents.Append(bodyDigest, EXPANDED_DIGEST_LENGTH);
}
nsresult rv = DigestHash(contents.get(), contents.Length(), algorithm);
if (NS_FAILED(rv)) {
return rv;
}
return ExpandToHex(mHashBuf, result, algorithm);
nsresult rv = MD5Hash(contents.get(), contents.Length());
if (NS_SUCCEEDED(rv)) rv = ExpandToHex(mHashBuf, result);
return rv;
}
nsresult nsHttpDigestAuth::ParseChallenge(const nsACString& aChallenge,
nsresult nsHttpDigestAuth::ParseChallenge(const char* challenge,
nsACString& realm, nsACString& domain,
nsACString& nonce, nsACString& opaque,
bool* stale, uint16_t* algorithm,
uint16_t* qop) {
// put an absurd, but maximum, length cap on the challenge so
// that calculations are 32 bit safe
if (aChallenge.Length() > 16000000) {
if (strlen(challenge) > 16000000) {
return NS_ERROR_INVALID_ARG;
}
const char* challenge = aChallenge.BeginReading();
const char* end = aChallenge.EndReading();
const char* p = challenge + 6; // first 6 characters are "Digest"
if (p >= end) {
return NS_ERROR_INVALID_ARG;
}
*stale = false;
*algorithm = ALGO_MD5; // default is MD5
*qop = 0;
for (;;) {
while (p < end && (*p == ',' || nsCRT::IsAsciiSpace(*p))) {
++p;
}
if (p >= end) {
break;
}
while (*p && (*p == ',' || nsCRT::IsAsciiSpace(*p))) ++p;
if (!*p) break;
// name
int32_t nameStart = (p - challenge);
while (p < end && !nsCRT::IsAsciiSpace(*p) && *p != '=') {
++p;
}
if (p >= end) {
return NS_ERROR_INVALID_ARG;
}
while (*p && !nsCRT::IsAsciiSpace(*p) && *p != '=') ++p;
if (!*p) return NS_ERROR_INVALID_ARG;
int32_t nameLength = (p - challenge) - nameStart;
while (p < end && (nsCRT::IsAsciiSpace(*p) || *p == '=')) {
++p;
}
if (p >= end) {
return NS_ERROR_INVALID_ARG;
}
while (*p && (nsCRT::IsAsciiSpace(*p) || *p == '=')) ++p;
if (!*p) return NS_ERROR_INVALID_ARG;
bool quoted = false;
if (*p == '"') {
@ -622,18 +562,12 @@ nsresult nsHttpDigestAuth::ParseChallenge(const nsACString& aChallenge,
int32_t valueStart = (p - challenge);
int32_t valueLength = 0;
if (quoted) {
while (p < end && *p != '"') {
++p;
}
if (p >= end || *p != '"') {
return NS_ERROR_INVALID_ARG;
}
while (*p && *p != '"') ++p;
if (*p != '"') return NS_ERROR_INVALID_ARG;
valueLength = (p - challenge) - valueStart;
++p;
} else {
while (p < end && !nsCRT::IsAsciiSpace(*p) && *p != ',') {
++p;
}
while (*p && !nsCRT::IsAsciiSpace(*p) && *p != ',') ++p;
valueLength = (p - challenge) - valueStart;
}
@ -652,52 +586,37 @@ nsresult nsHttpDigestAuth::ParseChallenge(const nsACString& aChallenge,
opaque.Assign(challenge + valueStart, valueLength);
} else if (nameLength == 5 &&
nsCRT::strncasecmp(challenge + nameStart, "stale", 5) == 0) {
if (nsCRT::strncasecmp(challenge + valueStart, "true", 4) == 0) {
if (nsCRT::strncasecmp(challenge + valueStart, "true", 4) == 0)
*stale = true;
} else {
else
*stale = 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) {
nsCRT::strncasecmp(challenge + valueStart, "MD5", 3) == 0)
*algorithm |= ALGO_MD5;
} else if (valueLength == 8 && nsCRT::strncasecmp(challenge + valueStart,
"MD5-sess", 8) == 0) {
else if (valueLength == 8 &&
nsCRT::strncasecmp(challenge + valueStart, "MD5-sess", 8) == 0)
*algorithm |= ALGO_MD5_SESS;
} else if (valueLength == 7 && nsCRT::strncasecmp(challenge + valueStart,
"SHA-256", 7) == 0) {
*algorithm |= ALGO_SHA256;
} else if (valueLength == 12 &&
nsCRT::strncasecmp(challenge + valueStart, "SHA-256-sess",
12) == 0) {
*algorithm |= ALGO_SHA256_SESS;
}
} else if (nameLength == 3 &&
nsCRT::strncasecmp(challenge + nameStart, "qop", 3) == 0) {
int32_t ipos = valueStart;
while (ipos < valueStart + valueLength) {
while (
ipos < valueStart + valueLength &&
(nsCRT::IsAsciiSpace(challenge[ipos]) || challenge[ipos] == ',')) {
while (ipos < valueStart + valueLength &&
(nsCRT::IsAsciiSpace(challenge[ipos]) || challenge[ipos] == ','))
ipos++;
}
int32_t algostart = ipos;
while (ipos < valueStart + valueLength &&
!nsCRT::IsAsciiSpace(challenge[ipos]) &&
challenge[ipos] != ',') {
!nsCRT::IsAsciiSpace(challenge[ipos]) && challenge[ipos] != ',')
ipos++;
}
if ((ipos - algostart) == 4 &&
nsCRT::strncasecmp(challenge + algostart, "auth", 4) == 0) {
nsCRT::strncasecmp(challenge + algostart, "auth", 4) == 0)
*qop |= QOP_AUTH;
} else if ((ipos - algostart) == 8 &&
nsCRT::strncasecmp(challenge + algostart, "auth-int", 8) ==
0) {
else if ((ipos - algostart) == 8 &&
nsCRT::strncasecmp(challenge + algostart, "auth-int", 8) == 0)
*qop |= QOP_AUTH_INT;
}
}
}
}

Просмотреть файл

@ -20,18 +20,12 @@ namespace net {
#define ALGO_SPECIFIED 0x01
#define ALGO_MD5 0x02
#define ALGO_MD5_SESS 0x04
#define ALGO_SHA256 0x08
#define ALGO_SHA256_SESS 0x10
#define QOP_AUTH 0x01
#define QOP_AUTH_INT 0x02
#define DIGEST_LENGTH 16
#define EXPANDED_DIGEST_LENGTH 32
#define NONCE_COUNT_LENGTH 8
#ifndef MD5_DIGEST_LENGTH
# define MD5_DIGEST_LENGTH 16
#endif
#ifndef SHA256_DIGEST_LENGTH
# define SHA256_DIGEST_LENGTH 32
#endif
//-----------------------------------------------------------------------------
// nsHttpDigestAuth
@ -46,21 +40,17 @@ class nsHttpDigestAuth final : public nsIHttpAuthenticator {
static already_AddRefed<nsIHttpAuthenticator> GetOrCreate();
[[nodiscard]] static nsresult ParseChallenge(
const nsACString& aChallenge, nsACString& realm, nsACString& domain,
nsACString& nonce, nsACString& opaque, bool* stale, uint16_t* algorithm,
uint16_t* qop);
protected:
~nsHttpDigestAuth() = default;
[[nodiscard]] nsresult ExpandToHex(const char* digest, char* result,
uint16_t algorithm);
[[nodiscard]] nsresult ExpandToHex(const char* digest, char* result);
[[nodiscard]] nsresult CalculateResponse(
const char* ha1_digest, const char* ha2_digest, uint16_t algorithm,
const nsCString& nonce, uint16_t qop, const char* nonce_count,
const nsCString& cnonce, char* result);
[[nodiscard]] nsresult CalculateResponse(const char* ha1_digest,
const char* ha2_digest,
const nsCString& nonce, uint16_t qop,
const char* nonce_count,
const nsCString& cnonce,
char* result);
[[nodiscard]] nsresult CalculateHA1(const nsCString& username,
const nsCString& password,
@ -71,12 +61,17 @@ class nsHttpDigestAuth final : public nsIHttpAuthenticator {
[[nodiscard]] nsresult CalculateHA2(const nsCString& http_method,
const nsCString& http_uri_path,
uint16_t algorithm, uint16_t qop,
const char* bodyDigest, char* result);
uint16_t qop, const char* body_digest,
char* result);
[[nodiscard]] nsresult ParseChallenge(const char* challenge,
nsACString& realm, nsACString& domain,
nsACString& nonce, nsACString& opaque,
bool* stale, uint16_t* algorithm,
uint16_t* qop);
// result is in mHashBuf
[[nodiscard]] nsresult DigestHash(const char* buf, uint32_t len,
uint16_t algorithm);
[[nodiscard]] nsresult MD5Hash(const char* buf, uint32_t len);
[[nodiscard]] nsresult GetMethodAndPath(nsIHttpAuthenticableChannel*, bool,
nsCString&, nsCString&);
@ -87,7 +82,7 @@ class nsHttpDigestAuth final : public nsIHttpAuthenticator {
protected:
nsCOMPtr<nsICryptoHash> mVerifier;
char mHashBuf[SHA256_DIGEST_LENGTH]{};
char mHashBuf[DIGEST_LENGTH];
static StaticRefPtr<nsHttpDigestAuth> gSingleton;
};

Просмотреть файл

@ -114,9 +114,8 @@ static bool CanUseDefaultCredentials(nsIHttpAuthenticableChannel* channel,
Unused << channel->GetURI(getter_AddRefs(uri));
bool allowNonFqdn;
if (NS_FAILED(prefs->GetBoolPref(kAllowNonFqdn, &allowNonFqdn))) {
if (NS_FAILED(prefs->GetBoolPref(kAllowNonFqdn, &allowNonFqdn)))
allowNonFqdn = false;
}
if (allowNonFqdn && uri && IsNonFqdn(uri)) {
LOG(("Host is non-fqdn, default credentials are allowed\n"));
return true;
@ -156,7 +155,7 @@ NS_IMPL_ISUPPORTS(nsHttpNTLMAuth, nsIHttpAuthenticator)
NS_IMETHODIMP
nsHttpNTLMAuth::ChallengeReceived(nsIHttpAuthenticableChannel* channel,
const nsACString& challenge, bool isProxyAuth,
const char* challenge, bool isProxyAuth,
nsISupports** sessionState,
nsISupports** continuationState,
bool* identityInvalid) {
@ -173,8 +172,7 @@ nsHttpNTLMAuth::ChallengeReceived(nsIHttpAuthenticableChannel* channel,
// Start a new auth sequence if the challenge is exactly "NTLM".
// If native NTLM auth apis are available and enabled through prefs,
// try to use them.
if (StringBeginsWith(challenge, "NTLM"_ns,
nsCaseInsensitiveCStringComparator)) {
if (nsCRT::strcasecmp(challenge, "NTLM") == 0) {
nsCOMPtr<nsIAuthModule> module;
// Check to see if we should default to our generic NTLM auth module
@ -251,31 +249,33 @@ nsHttpNTLMAuth::ChallengeReceived(nsIHttpAuthenticableChannel* channel,
NS_IMETHODIMP
nsHttpNTLMAuth::GenerateCredentialsAsync(
nsIHttpAuthenticableChannel* authChannel,
nsIHttpAuthenticatorCallback* aCallback, const nsACString& challenge,
bool isProxyAuth, const nsAString& domain, const nsAString& username,
const nsAString& password, nsISupports* sessionState,
nsIHttpAuthenticatorCallback* aCallback, const char* challenge,
bool isProxyAuth, const char16_t* domain, const char16_t* username,
const char16_t* password, nsISupports* sessionState,
nsISupports* continuationState, nsICancelable** aCancellable) {
return NS_ERROR_NOT_IMPLEMENTED;
}
NS_IMETHODIMP
nsHttpNTLMAuth::GenerateCredentials(
nsIHttpAuthenticableChannel* authChannel, const nsACString& aChallenge,
bool isProxyAuth, const nsAString& domain, const nsAString& user,
const nsAString& pass, nsISupports** sessionState,
nsISupports** continuationState, uint32_t* aFlags, nsACString& creds)
nsHttpNTLMAuth::GenerateCredentials(nsIHttpAuthenticableChannel* authChannel,
const char* challenge, bool isProxyAuth,
const char16_t* domain,
const char16_t* user, const char16_t* pass,
nsISupports** sessionState,
nsISupports** continuationState,
uint32_t* aFlags, char** creds)
{
LOG(("nsHttpNTLMAuth::GenerateCredentials\n"));
creds.Truncate();
*creds = nullptr;
*aFlags = 0;
// if user or password is empty, ChallengeReceived returned
// identityInvalid = false, that means we are using default user
// credentials; see nsAuthSSPI::Init method for explanation of this
// condition
if (user.IsEmpty() || pass.IsEmpty()) *aFlags = USING_INTERNAL_IDENTITY;
if (!user || !pass) *aFlags = USING_INTERNAL_IDENTITY;
nsresult rv;
nsCOMPtr<nsIAuthModule> module = do_QueryInterface(*continuationState, &rv);
@ -286,8 +286,7 @@ nsHttpNTLMAuth::GenerateCredentials(
Maybe<nsTArray<uint8_t>> certArray;
// initial challenge
if (StringBeginsWith(aChallenge, "NTLM"_ns,
nsCaseInsensitiveCStringComparator)) {
if (nsCRT::strcasecmp(challenge, "NTLM") == 0) {
// NTLM service name format is 'HTTP@host' for both http and https
nsCOMPtr<nsIURI> uri;
rv = authChannel->GetURI(getter_AddRefs(uri));
@ -301,7 +300,7 @@ nsHttpNTLMAuth::GenerateCredentials(
uint32_t reqFlags = nsIAuthModule::REQ_DEFAULT;
if (isProxyAuth) reqFlags |= nsIAuthModule::REQ_PROXY_AUTH;
rv = module->Init(serviceName, reqFlags, domain, user, pass);
rv = module->Init(serviceName.get(), reqFlags, domain, user, pass);
if (NS_FAILED(rv)) return rv;
// This update enables updated Windows machines (Win7 or patched previous
@ -353,19 +352,16 @@ nsHttpNTLMAuth::GenerateCredentials(
} else {
// decode challenge; skip past "NTLM " to the start of the base64
// encoded data.
if (aChallenge.Length() < 6) {
return NS_ERROR_UNEXPECTED; // bogus challenge
}
int len = strlen(challenge);
if (len < 6) return NS_ERROR_UNEXPECTED; // bogus challenge
challenge += 5;
len -= 5;
// strip off any padding (see bug 230351)
nsDependentCSubstring challenge(aChallenge, 5);
uint32_t len = challenge.Length();
while (len > 0 && challenge[len - 1] == '=') {
len--;
}
while (len && challenge[len - 1] == '=') len--;
// decode into the input secbuffer
rv = Base64Decode(challenge.BeginReading(), len, (char**)&inBuf, &inBufLen);
rv = Base64Decode(challenge, len, (char**)&inBuf, &inBufLen);
if (NS_FAILED(rv)) {
return rv;
}
@ -381,10 +377,10 @@ nsHttpNTLMAuth::GenerateCredentials(
if (!credsLen.isValid()) {
rv = NS_ERROR_FAILURE;
} else {
nsAutoCString encoded;
(void)Base64Decode(nsDependentCSubstring((char*)outBuf, outBufLen),
encoded);
creds = nsPrintfCString("NTLM %s", encoded.get());
*creds = (char*)moz_xmalloc(credsLen.value());
memcpy(*creds, "NTLM ", 5);
PL_Base64Encode((char*)outBuf, outBufLen, *creds + 5);
(*creds)[credsLen.value() - 1] = '\0'; // null terminate
}
// OK, we are done with |outBuf|

Просмотреть файл

@ -49,7 +49,7 @@ interface nsIHttpAuthenticator : nsISupports
*/
[must_use]
void challengeReceived(in nsIHttpAuthenticableChannel aChannel,
in ACString aChallenge,
in string aChallenge,
in boolean aProxyAuth,
inout nsISupports aSessionState,
inout nsISupports aContinuationState,
@ -96,11 +96,11 @@ interface nsIHttpAuthenticator : nsISupports
[must_use]
void generateCredentialsAsync(in nsIHttpAuthenticableChannel aChannel,
in nsIHttpAuthenticatorCallback aCallback,
in ACString aChallenge,
in string aChallenge,
in boolean aProxyAuth,
in AString aDomain,
in AString aUser,
in AString aPassword,
in wstring aDomain,
in wstring aUser,
in wstring aPassword,
in nsISupports aSessionState,
in nsISupports aContinuationState,
out nsICancelable aCancel);
@ -141,12 +141,12 @@ interface nsIHttpAuthenticator : nsISupports
* authenticator may return one of the generate flags bellow.
*/
[must_use]
ACString generateCredentials(in nsIHttpAuthenticableChannel aChannel,
in ACString aChallenge,
string generateCredentials(in nsIHttpAuthenticableChannel aChannel,
in string aChallenge,
in boolean aProxyAuth,
in AString aDomain,
in AString aUser,
in AString aPassword,
in wstring aDomain,
in wstring aUser,
in wstring aPassword,
inout nsISupports aSessionState,
inout nsISupports aContinuationState,
out unsigned long aFlags);

Просмотреть файл

@ -218,9 +218,7 @@ Requestor.prototype = {
prompt2: null,
};
function RealmTestRequestor(expected) {
this.expectedRealm = expected;
}
function RealmTestRequestor() {}
RealmTestRequestor.prototype = {
QueryInterface: ChromeUtils.generateQI([
@ -237,7 +235,7 @@ RealmTestRequestor.prototype = {
},
promptAuth: function realmtest_checkAuth(channel, level, authInfo) {
Assert.equal(authInfo.realm, this.expectedRealm);
Assert.equal(authInfo.realm, '"foo_bar');
return false;
},
@ -249,7 +247,6 @@ RealmTestRequestor.prototype = {
var listener = {
expectedCode: -1, // Uninitialized
nextTest: undefined,
onStartRequest: function test_onStartR(request) {
try {
@ -262,7 +259,7 @@ var listener = {
}
Assert.equal(request.responseStatus, this.expectedCode);
// The request should be succeeded if we expect 200
// The request should be succeeded iff we expect 200
Assert.equal(request.requestSucceeded, this.expectedCode == 200);
} catch (e) {
do_throw("Unexpected exception: " + e);
@ -278,7 +275,7 @@ var listener = {
onStopRequest: function test_onStopR(request, status) {
Assert.equal(status, Cr.NS_ERROR_ABORT);
this.nextTest();
moveToNextTest();
},
};
@ -296,238 +293,238 @@ function makeChan(url, loadingUrl) {
});
}
var tests = [
test_noauth,
test_returnfalse1,
test_wrongpw1,
test_prompt1,
test_prompt1CrossOrigin,
test_prompt2CrossOrigin,
test_returnfalse2,
test_wrongpw2,
test_prompt2,
test_ntlm,
test_basicrealm,
test_nonascii,
test_digest_noauth,
test_digest,
test_digest_bogus_user,
test_short_digest,
test_large_realm,
test_large_domain,
test_nonascii_xhr,
];
var current_test = 0;
var httpserv = null;
function setup() {
function moveToNextTest() {
if (current_test < tests.length - 1) {
// First, gotta clear the auth cache
Cc["@mozilla.org/network/http-auth-manager;1"]
.getService(Ci.nsIHttpAuthManager)
.clearAll();
current_test++;
tests[current_test]();
} else {
do_test_pending();
httpserv.stop(do_test_finished);
}
do_test_finished();
}
function run_test() {
httpserv = new HttpServer();
httpserv.registerPathHandler("/auth", authHandler);
httpserv.registerPathHandler("/auth/ntlm/simple", authNtlmSimple);
httpserv.registerPathHandler("/auth/realm", authRealm);
httpserv.registerPathHandler("/auth/non_ascii", authNonascii);
httpserv.registerPathHandler("/auth/digest_md5", authDigestMD5);
httpserv.registerPathHandler("/auth/digest_md5sess", authDigestMD5sess);
httpserv.registerPathHandler("/auth/digest_sha256", authDigestSHA256);
httpserv.registerPathHandler("/auth/digest_sha256sess", authDigestSHA256sess);
httpserv.registerPathHandler("/auth/digest_sha256_md5", authDigestSHA256_MD5);
httpserv.registerPathHandler("/auth/digest_md5_sha256", authDigestMD5_SHA256);
httpserv.registerPathHandler(
"/auth/digest_md5_sha256_oneline",
authDigestMD5_SHA256_oneline
);
httpserv.registerPathHandler("/auth/digest", authDigest);
httpserv.registerPathHandler("/auth/short_digest", authShortDigest);
httpserv.registerPathHandler("/largeRealm", largeRealm);
httpserv.registerPathHandler("/largeDomain", largeDomain);
httpserv.start(-1);
registerCleanupFunction(async () => {
await httpserv.stop();
});
}
setup();
async function openAndListen(chan) {
await new Promise(resolve => {
listener.nextTest = resolve;
chan.asyncOpen(listener);
});
Cc["@mozilla.org/network/http-auth-manager;1"]
.getService(Ci.nsIHttpAuthManager)
.clearAll();
tests[0]();
}
add_task(async function test_noauth() {
function test_noauth() {
var chan = makeChan(URL + "/auth", URL);
listener.expectedCode = 401; // Unauthorized
await openAndListen(chan);
});
chan.asyncOpen(listener);
add_task(async function test_returnfalse1() {
do_test_pending();
}
function test_returnfalse1() {
var chan = makeChan(URL + "/auth", URL);
chan.notificationCallbacks = new Requestor(FLAG_RETURN_FALSE, 1);
listener.expectedCode = 401; // Unauthorized
await openAndListen(chan);
});
chan.asyncOpen(listener);
add_task(async function test_wrongpw1() {
do_test_pending();
}
function test_wrongpw1() {
var chan = makeChan(URL + "/auth", URL);
chan.notificationCallbacks = new Requestor(FLAG_WRONG_PASSWORD, 1);
listener.expectedCode = 200; // OK
await openAndListen(chan);
});
chan.asyncOpen(listener);
add_task(async function test_prompt1() {
do_test_pending();
}
function test_prompt1() {
var chan = makeChan(URL + "/auth", URL);
chan.notificationCallbacks = new Requestor(0, 1);
listener.expectedCode = 200; // OK
await openAndListen(chan);
});
chan.asyncOpen(listener);
add_task(async function test_prompt1CrossOrigin() {
do_test_pending();
}
function test_prompt1CrossOrigin() {
var chan = makeChan(URL + "/auth", "http://example.org");
chan.notificationCallbacks = new Requestor(16, 1);
listener.expectedCode = 200; // OK
await openAndListen(chan);
});
chan.asyncOpen(listener);
add_task(async function test_prompt2CrossOrigin() {
do_test_pending();
}
function test_prompt2CrossOrigin() {
var chan = makeChan(URL + "/auth", "http://example.org");
chan.notificationCallbacks = new Requestor(16, 2);
listener.expectedCode = 200; // OK
await openAndListen(chan);
});
chan.asyncOpen(listener);
add_task(async function test_returnfalse2() {
do_test_pending();
}
function test_returnfalse2() {
var chan = makeChan(URL + "/auth", URL);
chan.notificationCallbacks = new Requestor(FLAG_RETURN_FALSE, 2);
listener.expectedCode = 401; // Unauthorized
await openAndListen(chan);
});
chan.asyncOpen(listener);
add_task(async function test_wrongpw2() {
do_test_pending();
}
function test_wrongpw2() {
var chan = makeChan(URL + "/auth", URL);
chan.notificationCallbacks = new Requestor(FLAG_WRONG_PASSWORD, 2);
listener.expectedCode = 200; // OK
await openAndListen(chan);
});
chan.asyncOpen(listener);
add_task(async function test_prompt2() {
do_test_pending();
}
function test_prompt2() {
var chan = makeChan(URL + "/auth", URL);
chan.notificationCallbacks = new Requestor(0, 2);
listener.expectedCode = 200; // OK
await openAndListen(chan);
});
chan.asyncOpen(listener);
add_task(async function test_ntlm() {
do_test_pending();
}
function test_ntlm() {
var chan = makeChan(URL + "/auth/ntlm/simple", URL);
chan.notificationCallbacks = new Requestor(FLAG_RETURN_FALSE, 2);
listener.expectedCode = 401; // Unauthorized
await openAndListen(chan);
});
chan.asyncOpen(listener);
add_task(async function test_basicrealm() {
do_test_pending();
}
function test_basicrealm() {
var chan = makeChan(URL + "/auth/realm", URL);
chan.notificationCallbacks = new RealmTestRequestor('"foo_bar');
chan.notificationCallbacks = new RealmTestRequestor();
listener.expectedCode = 401; // Unauthorized
await openAndListen(chan);
});
chan.asyncOpen(listener);
add_task(async function test_nonascii() {
do_test_pending();
}
function test_nonascii() {
var chan = makeChan(URL + "/auth/non_ascii", URL);
chan.notificationCallbacks = new Requestor(FLAG_NON_ASCII_USER_PASSWORD, 2);
listener.expectedCode = 200; // OK
await openAndListen(chan);
});
chan.asyncOpen(listener);
add_task(async function test_digest_noauth() {
var chan = makeChan(URL + "/auth/digest_md5", URL);
do_test_pending();
}
// chan.notificationCallbacks = new Requestor(FLAG_RETURN_FALSE, 2);
function test_nonascii_xhr() {
var xhr = new XMLHttpRequest();
xhr.open("GET", URL + "/auth/non_ascii", true, "é", "é");
xhr.onreadystatechange = function(event) {
if (xhr.readyState == 4) {
Assert.equal(xhr.status, 200);
moveToNextTest();
xhr.onreadystatechange = null;
}
};
xhr.send(null);
do_test_pending();
}
function test_digest_noauth() {
var chan = makeChan(URL + "/auth/digest", URL);
//chan.notificationCallbacks = new Requestor(FLAG_RETURN_FALSE, 2);
listener.expectedCode = 401; // Unauthorized
await openAndListen(chan);
});
chan.asyncOpen(listener);
add_task(async function test_digest_md5() {
var chan = makeChan(URL + "/auth/digest_md5", URL);
do_test_pending();
}
function test_digest() {
var chan = makeChan(URL + "/auth/digest", URL);
chan.notificationCallbacks = new Requestor(0, 2);
listener.expectedCode = 200; // OK
await openAndListen(chan);
});
chan.asyncOpen(listener);
add_task(async function test_digest_md5sess() {
var chan = makeChan(URL + "/auth/digest_md5sess", URL);
do_test_pending();
}
chan.notificationCallbacks = new Requestor(0, 2);
listener.expectedCode = 200; // OK
await openAndListen(chan);
});
add_task(async function test_digest_sha256() {
var chan = makeChan(URL + "/auth/digest_sha256", URL);
chan.notificationCallbacks = new Requestor(0, 2);
listener.expectedCode = 200; // OK
await openAndListen(chan);
});
add_task(async function test_digest_sha256sess() {
var chan = makeChan(URL + "/auth/digest_sha256sess", URL);
chan.notificationCallbacks = new Requestor(0, 2);
listener.expectedCode = 200; // OK
await openAndListen(chan);
});
add_task(async function test_digest_sha256_md5() {
var chan = makeChan(URL + "/auth/digest_sha256_md5", URL);
chan.notificationCallbacks = new Requestor(0, 2);
listener.expectedCode = 200; // OK
await openAndListen(chan);
});
add_task(async function test_digest_md5_sha256() {
var chan = makeChan(URL + "/auth/digest_md5_sha256", URL);
chan.notificationCallbacks = new Requestor(0, 2);
listener.expectedCode = 200; // OK
await openAndListen(chan);
});
add_task(async function test_digest_md5_sha256_oneline() {
var chan = makeChan(URL + "/auth/digest_md5_sha256_oneline", URL);
chan.notificationCallbacks = new Requestor(0, 2);
listener.expectedCode = 200; // OK
await openAndListen(chan);
});
add_task(async function test_digest_bogus_user() {
var chan = makeChan(URL + "/auth/digest_md5", URL);
function test_digest_bogus_user() {
var chan = makeChan(URL + "/auth/digest", URL);
chan.notificationCallbacks = new Requestor(FLAG_BOGUS_USER, 2);
listener.expectedCode = 401; // unauthorized
await openAndListen(chan);
});
chan.asyncOpen(listener);
do_test_pending();
}
// Test header "WWW-Authenticate: Digest" - bug 1338876.
add_task(async function test_short_digest() {
function test_short_digest() {
var chan = makeChan(URL + "/auth/short_digest", URL);
chan.notificationCallbacks = new Requestor(FLAG_NO_REALM, 2);
listener.expectedCode = 401; // OK
await openAndListen(chan);
});
chan.asyncOpen(listener);
// XXX(valentin): this makes tests fail if it's not run last. Why?
add_task(async function test_nonascii_xhr() {
await new Promise(resolve => {
let xhr = new XMLHttpRequest();
xhr.open("GET", URL + "/auth/non_ascii", true, "é", "é");
xhr.onreadystatechange = function(event) {
if (xhr.readyState == 4) {
Assert.equal(xhr.status, 200);
resolve();
xhr.onreadystatechange = null;
}
};
xhr.send(null);
});
});
do_test_pending();
}
// PATH HANDLERS
@ -625,7 +622,7 @@ function toHexString(charCode) {
return ("0" + charCode.toString(16)).slice(-2);
}
function HMD5(str) {
function H(str) {
var data = bytesFromString(str);
var ch = Cc["@mozilla.org/security/hash;1"].createInstance(Ci.nsICryptoHash);
ch.init(Ci.nsICryptoHash.MD5);
@ -634,218 +631,61 @@ function HMD5(str) {
return Array.from(hash, (c, i) => toHexString(hash.charCodeAt(i))).join("");
}
function HSHA256(str) {
var data = bytesFromString(str);
var ch = Cc["@mozilla.org/security/hash;1"].createInstance(Ci.nsICryptoHash);
ch.init(Ci.nsICryptoHash.SHA256);
ch.update(data, data.length);
var hash = ch.finish(false);
return Array.from(hash, (c, i) => toHexString(hash.charCodeAt(i))).join("");
}
//
// Digest handler
//
// /auth/digest
function authDigestMD5_helper(metadata, response, test_name) {
function authDigest(metadata, response) {
var nonce = "6f93719059cf8d568005727f3250e798";
var opaque = "1234opaque1234";
var cnonceRE = /cnonce="(\w+)"/;
var responseRE = /response="(\w+)"/;
var usernameRE = /username="(\w+)"/;
var authenticate =
'Digest realm="secret", domain="/", qop=auth,' +
'algorithm=MD5, nonce="' +
nonce +
'" opaque="' +
opaque +
'"';
var body;
var send_401 = 0;
// check creds if we have them
if (metadata.hasHeader("Authorization")) {
var cnonceRE = /cnonce="(\w+)"/;
var responseRE = /response="(\w+)"/;
var usernameRE = /username="(\w+)"/;
var algorithmRE = /algorithm=([\w-]+)/;
var auth = metadata.getHeader("Authorization");
var cnonce = auth.match(cnonceRE)[1];
var clientDigest = auth.match(responseRE)[1];
var username = auth.match(usernameRE)[1];
var algorithm = auth.match(algorithmRE)[1];
var nc = "00000001";
if (username != "guest") {
response.setStatusLine(metadata.httpVersion, 400, "bad request");
body = "should never get here";
} else if (
algorithm != null &&
algorithm != "MD5" &&
algorithm != "MD5-sess"
) {
response.setStatusLine(metadata.httpVersion, 400, "bad request");
body = "Algorithm must be same as provided in WWW-Authenticate header";
} else {
// see RFC2617 for the description of this calculation
var A1 = "guest:secret:guest";
if (algorithm == "MD5-sess") {
A1 = [HMD5(A1), nonce, cnonce].join(":");
}
var A2 = "GET:/auth/" + test_name;
var noncebits = [nonce, nc, cnonce, "auth", HMD5(A2)].join(":");
var digest = HMD5([HMD5(A1), noncebits].join(":"));
var A2 = "GET:/auth/digest";
var noncebits = [nonce, nc, cnonce, "auth", H(A2)].join(":");
var digest = H([H(A1), noncebits].join(":"));
if (clientDigest == digest) {
response.setStatusLine(metadata.httpVersion, 200, "OK, authorized");
body = "success";
} else {
send_401 = 1;
response.setStatusLine(metadata.httpVersion, 401, "Unauthorized");
response.setHeader("WWW-Authenticate", authenticate, false);
body = "auth failed";
}
}
} else {
// no header, send one
send_401 = 1;
response.setStatusLine(metadata.httpVersion, 401, "Unauthorized");
response.setHeader("WWW-Authenticate", authenticate, false);
body = "failed, no header";
}
if (send_401) {
var authenticate_md5 =
'Digest realm="secret", domain="/", qop=auth,' +
'algorithm=MD5, nonce="' +
nonce +
'" opaque="' +
opaque +
'"';
var authenticate_md5sess =
'Digest realm="secret", domain="/", qop=auth,' +
'algorithm=MD5, nonce="' +
nonce +
'" opaque="' +
opaque +
'"';
if (test_name == "digest_md5") {
response.setHeader("WWW-Authenticate", authenticate_md5, false);
} else if (test_name == "digest_md5sess") {
response.setHeader("WWW-Authenticate", authenticate_md5sess, false);
}
response.setStatusLine(metadata.httpVersion, 401, "Unauthorized");
}
response.bodyOutputStream.write(body, body.length);
}
function authDigestMD5(metadata, response) {
authDigestMD5_helper(metadata, response, "digest_md5");
}
function authDigestMD5sess(metadata, response) {
authDigestMD5_helper(metadata, response, "digest_md5sess");
}
function authDigestSHA256_helper(metadata, response, test_name) {
var nonce = "6f93719059cf8d568005727f3250e798";
var opaque = "1234opaque1234";
var body;
var send_401 = 0;
// check creds if we have them
if (metadata.hasHeader("Authorization")) {
var cnonceRE = /cnonce="(\w+)"/;
var responseRE = /response="(\w+)"/;
var usernameRE = /username="(\w+)"/;
var algorithmRE = /algorithm=([\w-]+)/;
var auth = metadata.getHeader("Authorization");
var cnonce = auth.match(cnonceRE)[1];
var clientDigest = auth.match(responseRE)[1];
var username = auth.match(usernameRE)[1];
var algorithm = auth.match(algorithmRE)[1];
var nc = "00000001";
if (username != "guest") {
response.setStatusLine(metadata.httpVersion, 400, "bad request");
body = "should never get here";
} else if (algorithm != "SHA-256" && algorithm != "SHA-256-sess") {
response.setStatusLine(metadata.httpVersion, 400, "bad request");
body = "Algorithm must be same as provided in WWW-Authenticate header";
} else {
// see RFC7616 for the description of this calculation
var A1 = "guest:secret:guest";
if (algorithm == "SHA-256-sess") {
A1 = [HSHA256(A1), nonce, cnonce].join(":");
}
var A2 = "GET:/auth/" + test_name;
var noncebits = [nonce, nc, cnonce, "auth", HSHA256(A2)].join(":");
var digest = HSHA256([HSHA256(A1), noncebits].join(":"));
if (clientDigest == digest) {
response.setStatusLine(metadata.httpVersion, 200, "OK, authorized");
body = "success";
} else {
send_401 = 1;
body = "auth failed";
}
}
} else {
// no header, send one
send_401 = 1;
body = "failed, no header";
}
if (send_401) {
var authenticate_sha256 =
'Digest realm="secret", domain="/", qop=auth, ' +
'algorithm=SHA-256, nonce="' +
nonce +
'", opaque="' +
opaque +
'"';
var authenticate_sha256sess =
'Digest realm="secret", domain="/", qop=auth, ' +
'algorithm=SHA-256-sess, nonce="' +
nonce +
'", opaque="' +
opaque +
'"';
var authenticate_md5 =
'Digest realm="secret", domain="/", qop=auth, ' +
'algorithm=MD5, nonce="' +
nonce +
'", opaque="' +
opaque +
'"';
if (test_name == "digest_sha256") {
response.setHeader("WWW-Authenticate", authenticate_sha256, false);
} else if (test_name == "digest_sha256sess") {
response.setHeader("WWW-Authenticate", authenticate_sha256sess, false);
} else if (test_name == "digest_md5_sha256") {
response.setHeader("WWW-Authenticate", authenticate_md5, false);
response.setHeader("WWW-Authenticate", authenticate_sha256, true);
} else if (test_name == "digest_md5_sha256_oneline") {
response.setHeader(
"WWW-Authenticate",
authenticate_md5 + " " + authenticate_sha256,
false
);
} else if (test_name == "digest_sha256_md5") {
response.setHeader("WWW-Authenticate", authenticate_sha256, false);
response.setHeader("WWW-Authenticate", authenticate_md5, true);
}
response.setStatusLine(metadata.httpVersion, 401, "Unauthorized");
}
response.bodyOutputStream.write(body, body.length);
}
function authDigestSHA256(metadata, response) {
authDigestSHA256_helper(metadata, response, "digest_sha256");
}
function authDigestSHA256sess(metadata, response) {
authDigestSHA256_helper(metadata, response, "digest_sha256sess");
}
function authDigestSHA256_MD5(metadata, response) {
authDigestSHA256_helper(metadata, response, "digest_sha256_md5");
}
function authDigestMD5_SHA256(metadata, response) {
authDigestSHA256_helper(metadata, response, "digest_md5_sha256");
}
function authDigestMD5_SHA256_oneline(metadata, response) {
authDigestSHA256_helper(metadata, response, "digest_md5_sha256_oneline");
}
function authShortDigest(metadata, response) {
// no header, send one
response.setStatusLine(metadata.httpVersion, 401, "Unauthorized");
@ -895,293 +735,20 @@ function largeDomain(metadata, response) {
response.bodyOutputStream.write(body, body.length);
}
add_task(async function test_large_realm() {
function test_large_realm() {
var chan = makeChan(URL + "/largeRealm", URL);
listener.expectedCode = 401; // Unauthorized
await openAndListen(chan);
});
chan.asyncOpen(listener);
add_task(async function test_large_domain() {
do_test_pending();
}
function test_large_domain() {
var chan = makeChan(URL + "/largeDomain", URL);
listener.expectedCode = 401; // Unauthorized
await openAndListen(chan);
});
chan.asyncOpen(listener);
async function add_parse_realm_testcase(testcase) {
httpserv.registerPathHandler("/parse_realm", (metadata, response) => {
response.setStatusLine(metadata.httpVersion, 401, "Unauthorized");
response.setHeader("WWW-Authenticate", testcase.input, false);
let body = "failed";
response.bodyOutputStream.write(body, body.length);
});
let chan = makeChan(URL + "/parse_realm", URL);
chan.notificationCallbacks = new RealmTestRequestor(testcase.realm);
listener.expectedCode = 401;
await openAndListen(chan);
do_test_pending();
}
add_task(async function simplebasic() {
await add_parse_realm_testcase({
input: `Basic realm="foo"`,
scheme: `Basic`,
realm: `foo`,
});
});
add_task(async function simplebasiclf() {
await add_parse_realm_testcase({
input: `Basic\r\n realm="foo"`,
scheme: `Basic`,
realm: `foo`,
});
});
add_task(async function simplebasicucase() {
await add_parse_realm_testcase({
input: `BASIC REALM="foo"`,
scheme: `Basic`,
realm: `foo`,
});
});
add_task(async function simplebasictok() {
await add_parse_realm_testcase({
input: `Basic realm=foo`,
scheme: `Basic`,
realm: `foo`,
});
});
add_task(async function simplebasictokbs() {
await add_parse_realm_testcase({
input: `Basic realm=\\f\\o\\o`,
scheme: `Basic`,
realm: `\\foo`,
});
});
add_task(async function simplebasicsq() {
await add_parse_realm_testcase({
input: `Basic realm='foo'`,
scheme: `Basic`,
realm: `'foo'`,
});
});
add_task(async function simplebasicpct() {
await add_parse_realm_testcase({
input: `Basic realm="foo%20bar"`,
scheme: `Basic`,
realm: `foo%20bar`,
});
});
add_task(async function simplebasiccomma() {
await add_parse_realm_testcase({
input: `Basic , realm="foo"`,
scheme: `Basic`,
realm: `foo`,
});
});
add_task(async function simplebasiccomma2() {
await add_parse_realm_testcase({
input: `Basic, realm="foo"`,
scheme: `Basic`,
realm: ``,
});
});
add_task(async function simplebasicnorealm() {
await add_parse_realm_testcase({
input: `Basic`,
scheme: `Basic`,
realm: ``,
});
});
add_task(async function simplebasic2realms() {
await add_parse_realm_testcase({
input: `Basic realm="foo", realm="bar"`,
scheme: `Basic`,
realm: `foo`,
});
});
add_task(async function simplebasicwsrealm() {
await add_parse_realm_testcase({
input: `Basic realm = "foo"`,
scheme: `Basic`,
realm: `foo`,
});
});
add_task(async function simplebasicrealmsqc() {
await add_parse_realm_testcase({
input: `Basic realm="\\f\\o\\o"`,
scheme: `Basic`,
realm: `foo`,
});
});
add_task(async function simplebasicrealmsqc2() {
await add_parse_realm_testcase({
input: `Basic realm="\\"foo\\""`,
scheme: `Basic`,
realm: `"foo"`,
});
});
add_task(async function simplebasicnewparam1() {
await add_parse_realm_testcase({
input: `Basic realm="foo", bar="xyz",, a=b,,,c=d`,
scheme: `Basic`,
realm: `foo`,
});
});
add_task(async function simplebasicnewparam2() {
await add_parse_realm_testcase({
input: `Basic bar="xyz", realm="foo"`,
scheme: `Basic`,
realm: `foo`,
});
});
add_task(async function simplebasicrealmiso88591() {
await add_parse_realm_testcase({
input: `Basic realm="foo-ä"`,
scheme: `Basic`,
realm: `foo-ä`,
});
});
add_task(async function simplebasicrealmutf8() {
await add_parse_realm_testcase({
input: `Basic realm="foo-ä"`,
scheme: `Basic`,
realm: `foo-ä`,
});
});
add_task(async function simplebasicrealmrfc2047() {
await add_parse_realm_testcase({
input: `Basic realm="=?ISO-8859-1?Q?foo-=E4?="`,
scheme: `Basic`,
realm: `=?ISO-8859-1?Q?foo-=E4?=`,
});
});
add_task(async function multibasicunknown() {
await add_parse_realm_testcase({
input: `Basic realm="basic", Newauth realm="newauth"`,
scheme: `Basic`,
realm: `basic`,
});
});
add_task(async function multibasicunknownnoparam() {
await add_parse_realm_testcase({
input: `Basic realm="basic", Newauth`,
scheme: `Basic`,
realm: `basic`,
});
});
add_task(async function multibasicunknown2() {
await add_parse_realm_testcase({
input: `Newauth realm="newauth", Basic realm="basic"`,
scheme: `Basic`,
realm: `basic`,
});
});
add_task(async function multibasicunknown2np() {
await add_parse_realm_testcase({
input: `Newauth, Basic realm="basic"`,
scheme: `Basic`,
realm: `basic`,
});
});
add_task(async function multibasicunknown2mf() {
httpserv.registerPathHandler("/parse_realm", (metadata, response) => {
response.setStatusLine(metadata.httpVersion, 401, "Unauthorized");
response.setHeader("WWW-Authenticate", `Newauth realm="newauth"`, false);
response.setHeader("WWW-Authenticate", `Basic realm="basic"`, false);
let body = "failed";
response.bodyOutputStream.write(body, body.length);
});
let chan = makeChan(URL + "/parse_realm", URL);
chan.notificationCallbacks = new RealmTestRequestor("basic");
listener.expectedCode = 401;
await openAndListen(chan);
});
add_task(async function multibasicempty() {
await add_parse_realm_testcase({
input: `,Basic realm="basic"`,
scheme: `Basic`,
realm: `basic`,
});
});
add_task(async function multibasicqs() {
await add_parse_realm_testcase({
input: `Newauth realm="apps", type=1, title="Login to \"apps\"", Basic realm="simple"`,
scheme: `Basic`,
realm: `simple`,
});
});
add_task(async function multidisgscheme() {
await add_parse_realm_testcase({
input: `Newauth realm="Newauth Realm", basic=foo, Basic realm="Basic Realm"`,
scheme: `Basic`,
realm: `Basic Realm`,
});
});
add_task(async function unknown() {
await add_parse_realm_testcase({
input: `Newauth param="value"`,
scheme: `Basic`,
realm: ``,
});
});
add_task(async function parametersnotrequired() {
await add_parse_realm_testcase({ input: `A, B`, scheme: `Basic`, realm: `` });
});
add_task(async function disguisedrealm() {
await add_parse_realm_testcase({
input: `Basic foo="realm=nottherealm", realm="basic"`,
scheme: `Basic`,
realm: `basic`,
});
});
add_task(async function disguisedrealm2() {
await add_parse_realm_testcase({
input: `Basic nottherealm="nottherealm", realm="basic"`,
scheme: `Basic`,
realm: `basic`,
});
});
add_task(async function missingquote() {
await add_parse_realm_testcase({
input: `Basic realm="basic`,
scheme: `Basic`,
realm: `basic`,
});
});

Просмотреть файл

@ -184,11 +184,10 @@ static void LogBuf(const char* tag, const uint8_t* buf, uint32_t bufLen) {
snprintf(line + len, sizeof(line) - len, " ");
for (i = 0; i < count; ++i) {
len = strlen(line);
if (isprint(buf[i])) {
if (isprint(buf[i]))
snprintf(line + len, sizeof(line) - len, "%c", buf[i]);
} else {
else
snprintf(line + len, sizeof(line) - len, ".");
}
}
PR_LogPrint("%s\n", line);
@ -408,19 +407,17 @@ static nsresult ParseType2Msg(const void* inBuf, uint32_t inLen,
//
if (inLen < NTLM_TYPE2_HEADER_LEN) return NS_ERROR_UNEXPECTED;
const auto* cursor = static_cast<const uint8_t*>(inBuf);
auto cursor = static_cast<const uint8_t*>(inBuf);
// verify NTLMSSP signature
if (memcmp(cursor, NTLM_SIGNATURE, sizeof(NTLM_SIGNATURE)) != 0) {
if (memcmp(cursor, NTLM_SIGNATURE, sizeof(NTLM_SIGNATURE)) != 0)
return NS_ERROR_UNEXPECTED;
}
cursor += sizeof(NTLM_SIGNATURE);
// verify Type-2 marker
if (memcmp(cursor, NTLM_TYPE2_MARKER, sizeof(NTLM_TYPE2_MARKER)) != 0) {
if (memcmp(cursor, NTLM_TYPE2_MARKER, sizeof(NTLM_TYPE2_MARKER)) != 0)
return NS_ERROR_UNEXPECTED;
}
cursor += sizeof(NTLM_TYPE2_MARKER);
@ -491,7 +488,7 @@ static nsresult GenerateType3Msg(const nsString& domain,
// inBuf contains Type-2 msg (the challenge) from server
MOZ_ASSERT(NS_IsMainThread());
nsresult rv;
Type2Msg msg{};
Type2Msg msg;
rv = ParseType2Msg(inBuf, inLen, &msg);
if (NS_FAILED(rv)) return rv;
@ -500,7 +497,8 @@ static nsresult GenerateType3Msg(const nsString& domain,
// There is no negotiation for NTLMv2, so we just do it unless we are forced
// by explict user configuration to use the older DES-based cryptography.
bool ntlmv2 = !mozilla::StaticPrefs::network_auth_force_generic_ntlm_v1();
bool ntlmv2 =
mozilla::StaticPrefs::network_auth_force_generic_ntlm_v1() == false;
// temporary buffers for unicode strings
#ifdef IS_BIG_ENDIAN
@ -792,7 +790,7 @@ static nsresult GenerateType3Msg(const nsString& domain,
return rv;
}
const auto* sessionHash = mozilla::BitwiseCast<const uint8_t*, const char*>(
auto sessionHash = mozilla::BitwiseCast<const uint8_t*, const char*>(
sessionHashString.get());
LogBuf("NTLM2 effective key: ", sessionHash, 8);
@ -918,9 +916,9 @@ nsresult nsNTLMAuthModule::InitTest() {
}
NS_IMETHODIMP
nsNTLMAuthModule::Init(const nsACString& serviceName, uint32_t serviceFlags,
const nsAString& domain, const nsAString& username,
const nsAString& password) {
nsNTLMAuthModule::Init(const char* /*serviceName*/, uint32_t serviceFlags,
const char16_t* domain, const char16_t* username,
const char16_t* password) {
MOZ_ASSERT((serviceFlags & ~nsIAuthModule::REQ_PROXY_AUTH) ==
nsIAuthModule::REQ_DEFAULT,
"Unexpected service flags");
@ -1003,11 +1001,10 @@ nsNTLMAuthModule::Wrap(const void* inToken, uint32_t inTokenLen,
static uint8_t des_setkeyparity(uint8_t x) {
if ((((x >> 7) ^ (x >> 6) ^ (x >> 5) ^ (x >> 4) ^ (x >> 3) ^ (x >> 2) ^
(x >> 1)) &
0x01) == 0) {
0x01) == 0)
x |= 0x01;
} else {
else
x &= 0xfe;
}
return x;
}

Просмотреть файл

@ -51,35 +51,31 @@ TEST(Tokenizer, HTTPResponse)
p.SkipWhites();
p.Record();
while (p.Next(t) && t.Type() != Tokenizer::TOKEN_EOL) {
while (p.Next(t) && t.Type() != Tokenizer::TOKEN_EOL)
;
}
EXPECT_FALSE(p.HasFailed());
nsAutoCString h;
p.Claim(h);
EXPECT_TRUE(h == "Not modified");
p.Record();
while (p.CheckChar(HttpHeaderCharacter)) {
while (p.CheckChar(HttpHeaderCharacter))
;
}
p.Claim(h, Tokenizer::INCLUDE_LAST);
EXPECT_TRUE(h == "ETag");
p.SkipWhites();
EXPECT_TRUE(p.CheckChar(':'));
p.SkipWhites();
p.Record();
while (p.Next(t) && t.Type() != Tokenizer::TOKEN_EOL) {
while (p.Next(t) && t.Type() != Tokenizer::TOKEN_EOL)
;
}
EXPECT_FALSE(p.HasFailed());
p.Claim(h);
EXPECT_TRUE(h == "hallo");
p.Record();
while (p.CheckChar(HttpHeaderCharacter)) {
while (p.CheckChar(HttpHeaderCharacter))
;
}
p.Claim(h, Tokenizer::INCLUDE_LAST);
EXPECT_TRUE(h == "Content-Length");
p.SkipWhites();
@ -92,9 +88,8 @@ TEST(Tokenizer, HTTPResponse)
EXPECT_TRUE(p.CheckEOL());
p.Record();
while (p.Next(t) && t.Type() != Tokenizer::TOKEN_EOF) {
while (p.Next(t) && t.Type() != Tokenizer::TOKEN_EOF)
;
}
nsAutoCString b;
p.Claim(b);
EXPECT_TRUE(b == "This is the body");
@ -394,9 +389,8 @@ TEST(Tokenizer, HasFailed)
Tokenizer p1("a b"_ns);
while (p1.Next(t) && t.Type() != Tokenizer::TOKEN_CHAR) {
while (p1.Next(t) && t.Type() != Tokenizer::TOKEN_CHAR)
;
}
EXPECT_TRUE(p1.HasFailed());
Tokenizer p2("a b ?!c"_ns);
@ -423,9 +417,8 @@ TEST(Tokenizer, HasFailed)
EXPECT_TRUE(p2.Check(t));
EXPECT_FALSE(p2.HasFailed());
while (p2.Next(t) && t.Type() != Tokenizer::TOKEN_CHAR) {
while (p2.Next(t) && t.Type() != Tokenizer::TOKEN_CHAR)
;
}
EXPECT_TRUE(p2.HasFailed());
}
@ -945,7 +938,7 @@ TEST(Tokenizer, CustomRaw)
TEST(Tokenizer, Incremental)
{
using Token = IncrementalTokenizer::Token;
typedef IncrementalTokenizer::Token Token;
int test = 0;
IncrementalTokenizer i(
@ -981,8 +974,8 @@ TEST(Tokenizer, Incremental)
});
constexpr auto input = "test1,test2,,,test3"_ns;
const auto* cur = input.BeginReading();
const auto* end = input.EndReading();
auto cur = input.BeginReading();
auto end = input.EndReading();
for (; cur < end; ++cur) {
i.FeedInput(nsDependentCSubstring(cur, 1));
}
@ -994,7 +987,7 @@ TEST(Tokenizer, Incremental)
TEST(Tokenizer, IncrementalRollback)
{
using Token = IncrementalTokenizer::Token;
typedef IncrementalTokenizer::Token Token;
int test = 0;
IncrementalTokenizer i(
@ -1034,8 +1027,8 @@ TEST(Tokenizer, IncrementalRollback)
});
constexpr auto input = "test1,test2,,,test3"_ns;
const auto* cur = input.BeginReading();
const auto* end = input.EndReading();
auto cur = input.BeginReading();
auto end = input.EndReading();
for (; cur < end; ++cur) {
i.FeedInput(nsDependentCSubstring(cur, 1));
}
@ -1047,7 +1040,7 @@ TEST(Tokenizer, IncrementalRollback)
TEST(Tokenizer, IncrementalNeedMoreInput)
{
using Token = IncrementalTokenizer::Token;
typedef IncrementalTokenizer::Token Token;
int test = 0;
IncrementalTokenizer i(
@ -1085,8 +1078,8 @@ TEST(Tokenizer, IncrementalNeedMoreInput)
});
constexpr auto input = "a bb,c"_ns;
const auto* cur = input.BeginReading();
const auto* end = input.EndReading();
auto cur = input.BeginReading();
auto end = input.EndReading();
nsresult rv;
for (; cur < end; ++cur) {
@ -1106,7 +1099,7 @@ TEST(Tokenizer, IncrementalNeedMoreInput)
TEST(Tokenizer, IncrementalCustom)
{
using Token = IncrementalTokenizer::Token;
typedef IncrementalTokenizer::Token Token;
int test = 0;
Token custom;
@ -1141,7 +1134,7 @@ TEST(Tokenizer, IncrementalCustom)
TEST(Tokenizer, IncrementalCustomRaw)
{
using Token = IncrementalTokenizer::Token;
typedef IncrementalTokenizer::Token Token;
int test = 0;
Token custom;
@ -1184,8 +1177,8 @@ TEST(Tokenizer, IncrementalCustomRaw)
i.SetTokenizingMode(Tokenizer::Mode::CUSTOM_ONLY);
constexpr auto input = "test1,test2!,,test3test2tes"_ns;
const auto* cur = input.BeginReading();
const auto* end = input.EndReading();
auto cur = input.BeginReading();
auto end = input.EndReading();
for (; cur < end; ++cur) {
i.FeedInput(nsDependentCSubstring(cur, 1));
}
@ -1197,7 +1190,7 @@ TEST(Tokenizer, IncrementalCustomRaw)
TEST(Tokenizer, IncrementalCustomRemove)
{
using Token = IncrementalTokenizer::Token;
typedef IncrementalTokenizer::Token Token;
int test = 0;
Token custom;
@ -1230,7 +1223,7 @@ TEST(Tokenizer, IncrementalCustomRemove)
TEST(Tokenizer, IncrementalBuffering1)
{
using Token = IncrementalTokenizer::Token;
typedef IncrementalTokenizer::Token Token;
int test = 0;
Token custom;
@ -1290,7 +1283,7 @@ TEST(Tokenizer, IncrementalBuffering1)
TEST(Tokenizer, IncrementalBuffering2)
{
using Token = IncrementalTokenizer::Token;
typedef IncrementalTokenizer::Token Token;
int test = 0;
Token custom;