diff --git a/extensions/gio/nsGIOProtocolHandler.cpp b/extensions/gio/nsGIOProtocolHandler.cpp index 1ccece1fac72..1800f59119a2 100644 --- a/extensions/gio/nsGIOProtocolHandler.cpp +++ b/extensions/gio/nsGIOProtocolHandler.cpp @@ -826,11 +826,11 @@ mount_operation_ask_password (GMountOperation *mount_op, if (flags & G_ASK_PASSWORD_NEED_USERNAME) { if (!realm.IsEmpty()) { const char16_t *strings[] = { realm.get(), dispHost.get() }; - bundle->FormatStringFromName(MOZ_UTF16("EnterLoginForRealm"), + bundle->FormatStringFromName(MOZ_UTF16("EnterLoginForRealm2"), strings, 2, getter_Copies(nsmessage)); } else { const char16_t *strings[] = { dispHost.get() }; - bundle->FormatStringFromName(MOZ_UTF16("EnterUserPasswordFor"), + bundle->FormatStringFromName(MOZ_UTF16("EnterUserPasswordFor2"), strings, 1, getter_Copies(nsmessage)); } } else { diff --git a/mobile/android/components/PromptService.js b/mobile/android/components/PromptService.js index f6167a450ace..9dd0b3b33704 100644 --- a/mobile/android/components/PromptService.js +++ b/mobile/android/components/PromptService.js @@ -676,6 +676,8 @@ var PromptUtils = { makeDialogText: function pu_makeDialogText(aChannel, aAuthInfo) { let isProxy = (aAuthInfo.flags & Ci.nsIAuthInformation.AUTH_PROXY); let isPassOnly = (aAuthInfo.flags & Ci.nsIAuthInformation.ONLY_PASSWORD); + let isCrossOrig = (aAuthInfo.flags & + Ci.nsIAuthInformation.CROSS_ORIGIN_SUB_RESOURCE); let username = aAuthInfo.username; let [displayHost, realm] = this.getAuthTarget(aChannel, aAuthInfo); @@ -692,14 +694,17 @@ var PromptUtils = { } let text; - if (isProxy) - text = this.bundle.formatStringFromName("EnterLoginForProxy", [realm, displayHost], 2); - else if (isPassOnly) + if (isProxy) { + text = this.bundle.formatStringFromName("EnterLoginForProxy2", [realm, displayHost], 2); + } else if (isPassOnly) { text = this.bundle.formatStringFromName("EnterPasswordFor", [username, displayHost], 2); - else if (!realm) - text = this.bundle.formatStringFromName("EnterUserPasswordFor", [displayHost], 1); - else - text = this.bundle.formatStringFromName("EnterLoginForRealm", [realm, displayHost], 2); + } else if (isCrossOrig) { + text = this.bundle.formatStringFromName("EnterUserPasswordForCrossOrigin", [displayHost], 1); + } else if (!realm) { + text = this.bundle.formatStringFromName("EnterUserPasswordFor2", [displayHost], 1); + } else { + text = this.bundle.formatStringFromName("EnterLoginForRealm2", [realm, displayHost], 2); + } return text; }, diff --git a/netwerk/base/nsIAuthInformation.idl b/netwerk/base/nsIAuthInformation.idl index da79503771b3..484d59a8c410 100644 --- a/netwerk/base/nsIAuthInformation.idl +++ b/netwerk/base/nsIAuthInformation.idl @@ -54,6 +54,12 @@ interface nsIAuthInformation : nsISupports * @see also RFC 2616, Section 10.4.2 */ const uint32_t PREVIOUS_FAILED = 16; + + /** + * A cross-origin sub-resource requests an authentication. + * The message presented to users must reflect that. + */ + const uint32_t CROSS_ORIGIN_SUB_RESOURCE = 32; /* @} */ /** diff --git a/netwerk/protocol/http/nsHttpChannelAuthProvider.cpp b/netwerk/protocol/http/nsHttpChannelAuthProvider.cpp index d312b2a87990..a38b727be6d9 100644 --- a/netwerk/protocol/http/nsHttpChannelAuthProvider.cpp +++ b/netwerk/protocol/http/nsHttpChannelAuthProvider.cpp @@ -40,6 +40,7 @@ namespace net { #define HTTP_AUTH_DIALOG_TOP_LEVEL_DOC 0 #define HTTP_AUTH_DIALOG_SAME_ORIGIN_SUBRESOURCE 1 #define HTTP_AUTH_DIALOG_CROSS_ORIGIN_SUBRESOURCE 2 +#define HTTP_AUTH_DIALOG_XHR 3 #define HTTP_AUTH_BASIC_INSECURE 0 #define HTTP_AUTH_BASIC_SECURE 1 @@ -72,6 +73,7 @@ nsHttpChannelAuthProvider::nsHttpChannelAuthProvider() , mTriedProxyAuth(false) , mTriedHostAuth(false) , mSuppressDefensiveAuth(false) + , mCrossOrigin(false) , mHttpHandler(gHttpHandler) { } @@ -795,8 +797,12 @@ nsHttpChannelAuthProvider::GetCredentialsForChallenge(const char *challenge, // blocked for all sub-resources, blocked for cross-origin // sub-resources, or always allowed for sub-resources. // For more details look at the bug 647010. + // BlockPrompt will set mCrossOrigin parameter as well. if (BlockPrompt()) { - return NS_ERROR_ABORT; + LOG(("nsHttpChannelAuthProvider::GetCredentialsForChallenge: " + "Prompt is blocked [this=%p pref=%d]\n", + this, sAuthAllowPref)); + return NS_ERROR_ABORT; } // at this point we are forced to interact with the user to get @@ -852,61 +858,72 @@ nsHttpChannelAuthProvider::BlockPrompt() MOZ_ASSERT(chanInternal); if (chanInternal->GetBlockAuthPrompt()) { + LOG(("nsHttpChannelAuthProvider::BlockPrompt: Prompt is blocked " + "[this=%p channel=%p]\n", this, mAuthChannel)); return true; } nsCOMPtr chan = do_QueryInterface(mAuthChannel); nsCOMPtr loadInfo; chan->GetLoadInfo(getter_AddRefs(loadInfo)); - if (!loadInfo) { - return false; + + // We will treat loads w/o loadInfo as a top level document. + bool topDoc = true; + bool xhr = false; + + if (loadInfo) { + if (loadInfo->GetExternalContentPolicyType() != + nsIContentPolicy::TYPE_DOCUMENT) { + topDoc = false; + } + if (loadInfo->GetExternalContentPolicyType() == + nsIContentPolicy::TYPE_XMLHTTPREQUEST) { + xhr = true; + } + + if (!topDoc && !xhr) { + nsCOMPtr topURI; + chanInternal->GetTopWindowURI(getter_AddRefs(topURI)); + + if (!topURI) { + // If we do not have topURI try the loadingPrincipal. + nsCOMPtr loadingPrinc = loadInfo->LoadingPrincipal(); + if (loadingPrinc) { + loadingPrinc->GetURI(getter_AddRefs(topURI)); + } + } + + if (!NS_SecurityCompareURIs(topURI, mURI, true)) { + mCrossOrigin = true; + } + } } if (gHttpHandler->IsTelemetryEnabled()) { - if (loadInfo->GetExternalContentPolicyType() == nsIContentPolicy::TYPE_DOCUMENT) { - Telemetry::Accumulate(Telemetry::HTTP_AUTH_DIALOG_STATS, - HTTP_AUTH_DIALOG_TOP_LEVEL_DOC); - } else { - nsCOMPtr loadingPrincipal = loadInfo->LoadingPrincipal(); - if (loadingPrincipal) { - if (NS_SUCCEEDED(loadingPrincipal->CheckMayLoad(mURI, false, false))) { + if (topDoc) { Telemetry::Accumulate(Telemetry::HTTP_AUTH_DIALOG_STATS, - HTTP_AUTH_DIALOG_SAME_ORIGIN_SUBRESOURCE); - } else { + HTTP_AUTH_DIALOG_TOP_LEVEL_DOC); + } else if (xhr) { Telemetry::Accumulate(Telemetry::HTTP_AUTH_DIALOG_STATS, - HTTP_AUTH_DIALOG_CROSS_ORIGIN_SUBRESOURCE); - } + HTTP_AUTH_DIALOG_XHR); + } else if (!mCrossOrigin) { + Telemetry::Accumulate(Telemetry::HTTP_AUTH_DIALOG_STATS, + HTTP_AUTH_DIALOG_SAME_ORIGIN_SUBRESOURCE); + } else { + Telemetry::Accumulate(Telemetry::HTTP_AUTH_DIALOG_STATS, + HTTP_AUTH_DIALOG_CROSS_ORIGIN_SUBRESOURCE); } - } - } - - // Allow if it is the top-level document or xhr. - if ((loadInfo->GetExternalContentPolicyType() == nsIContentPolicy::TYPE_DOCUMENT) || - (loadInfo->GetExternalContentPolicyType() == nsIContentPolicy::TYPE_XMLHTTPREQUEST)) { - return false; } switch (sAuthAllowPref) { case SUBRESOURCE_AUTH_DIALOG_DISALLOW_ALL: // Do not open the http-authentication credentials dialog for // the sub-resources. - return true; - break; + return !topDoc && !xhr; case SUBRESOURCE_AUTH_DIALOG_DISALLOW_CROSS_ORIGIN: - // Do not open the http-authentication credentials dialog for + // Open the http-authentication credentials dialog for // the sub-resources only if they are not cross-origin. - { - nsCOMPtr loadingPrincipal = - loadInfo->LoadingPrincipal(); - if (!loadingPrincipal) { - return false; - } - - if (NS_FAILED(loadingPrincipal->CheckMayLoad(mURI, false, false))) { - return true; - } - } - break; + return !topDoc && !xhr && mCrossOrigin; case SUBRESOURCE_AUTH_DIALOG_ALLOW_ALL: // Allow the http-authentication dialog. return false; @@ -1100,6 +1117,10 @@ nsHttpChannelAuthProvider::PromptForIdentity(uint32_t level, if (authFlags & nsIHttpAuthenticator::IDENTITY_INCLUDES_DOMAIN) promptFlags |= nsIAuthInformation::NEED_DOMAIN; + if (mCrossOrigin) { + promptFlags |= nsIAuthInformation::CROSS_ORIGIN_SUB_RESOURCE; + } + RefPtr holder = new nsHTTPAuthInformation(promptFlags, realmU, nsDependentCString(authType)); diff --git a/netwerk/protocol/http/nsHttpChannelAuthProvider.h b/netwerk/protocol/http/nsHttpChannelAuthProvider.h index c03bfb38ec55..95d8e1200fc4 100644 --- a/netwerk/protocol/http/nsHttpChannelAuthProvider.h +++ b/netwerk/protocol/http/nsHttpChannelAuthProvider.h @@ -154,6 +154,10 @@ private: uint32_t mTriedHostAuth : 1; uint32_t mSuppressDefensiveAuth : 1; + // If a cross-origin sub-resource is being loaded, this flag will be set. + // In that case, the prompt text will be different to warn users. + uint32_t mCrossOrigin : 1; + RefPtr mHttpHandler; // keep gHttpHandler alive // A variable holding the preference settings to whether to open HTTP diff --git a/netwerk/test/unit/test_authentication.js b/netwerk/test/unit/test_authentication.js index 3657485f0872..c61db770dbf2 100644 --- a/netwerk/test/unit/test_authentication.js +++ b/netwerk/test/unit/test_authentication.js @@ -21,6 +21,7 @@ const FLAG_RETURN_FALSE = 1 << 0; const FLAG_WRONG_PASSWORD = 1 << 1; const FLAG_BOGUS_USER = 1 << 2; const FLAG_PREVIOUS_FAILED = 1 << 3; +const CROSS_ORIGIN = 1 << 4; const nsIAuthPrompt2 = Components.interfaces.nsIAuthPrompt2; const nsIAuthInformation = Components.interfaces.nsIAuthInformation; @@ -52,8 +53,15 @@ AuthPrompt1.prototype = { { // Note that the realm here isn't actually the realm. it's a pw mgr key. do_check_eq(URL + " (" + this.expectedRealm + ")", realm); - if (text.indexOf(this.expectedRealm) == -1) - do_throw("Text must indicate the realm"); + if (!(this.flags & CROSS_ORIGIN)) { + if (text.indexOf(this.expectedRealm) == -1) { + do_throw("Text must indicate the realm"); + } + } else { + if (text.indexOf(this.expectedRealm) != -1) { + do_throw("There should not be realm for cross origin"); + } + } if (text.indexOf("localhost") == -1) do_throw("Text must indicate the hostname"); if (text.indexOf(String(PORT)) == -1) @@ -122,10 +130,13 @@ AuthPrompt2.prototype = { if (this.flags & FLAG_PREVIOUS_FAILED) expectedFlags |= nsIAuthInformation.PREVIOUS_FAILED; + if (this.flags & CROSS_ORIGIN) + expectedFlags |= nsIAuthInformation.CROSS_ORIGIN_SUB_RESOURCE; + if (isNTLM) expectedFlags |= nsIAuthInformation.NEED_DOMAIN; - const kAllKnownFlags = 31; // Don't fail test for newly added flags + const kAllKnownFlags = 63; // Don't fail test for newly added flags do_check_eq(expectedFlags, authInfo.flags & kAllKnownFlags); var expectedScheme = isNTLM ? "ntlm" : isDigest ? "digest" : "basic"; @@ -274,12 +285,22 @@ var listener = { } }; -function makeChan(url) { - return NetUtil.newChannel({uri: url, loadUsingSystemPrincipal: true}) - .QueryInterface(Components.interfaces.nsIHttpChannel); +function makeChan(url, loadingUrl) { + var ios = Cc["@mozilla.org/network/io-service;1"]. + getService(Ci.nsIIOService); + var ssm = Cc["@mozilla.org/scriptsecuritymanager;1"] + .getService(Ci.nsIScriptSecurityManager); + var principal = ssm.createCodebasePrincipal(ios.newURI(loadingUrl, null, null), {}); + return NetUtil.newChannel( + { uri: url, loadingPrincipal: principal, + securityFlags: Ci.nsILoadInfo.SEC_NORMAL | + Ci.nsILoadInfo.SEC_ALLOW_CROSS_ORIGIN_DATA_IS_NULL, + contentPolicyType: Components.interfaces.nsIContentPolicy.TYPE_OTHER + }); } 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_digest_noauth, test_digest, test_digest_bogus_user, test_large_realm, test_large_domain]; @@ -304,7 +325,7 @@ function run_test() { } function test_noauth() { - var chan = makeChan(URL + "/auth"); + var chan = makeChan(URL + "/auth", URL); listener.expectedCode = 401; // Unauthorized chan.asyncOpen2(listener); @@ -313,7 +334,7 @@ function test_noauth() { } function test_returnfalse1() { - var chan = makeChan(URL + "/auth"); + var chan = makeChan(URL + "/auth", URL); chan.notificationCallbacks = new Requestor(FLAG_RETURN_FALSE, 1); listener.expectedCode = 401; // Unauthorized @@ -323,7 +344,7 @@ function test_returnfalse1() { } function test_wrongpw1() { - var chan = makeChan(URL + "/auth"); + var chan = makeChan(URL + "/auth", URL); chan.notificationCallbacks = new Requestor(FLAG_WRONG_PASSWORD, 1); listener.expectedCode = 200; // OK @@ -333,7 +354,7 @@ function test_wrongpw1() { } function test_prompt1() { - var chan = makeChan(URL + "/auth"); + var chan = makeChan(URL + "/auth", URL); chan.notificationCallbacks = new Requestor(0, 1); listener.expectedCode = 200; // OK @@ -342,8 +363,28 @@ function test_prompt1() { do_test_pending(); } +function test_prompt1CrossOrigin() { + var chan = makeChan(URL + "/auth", "http://example.org"); + + chan.notificationCallbacks = new Requestor(16, 1); + listener.expectedCode = 200; // OK + chan.asyncOpen2(listener); + + do_test_pending(); +} + +function test_prompt2CrossOrigin() { + var chan = makeChan(URL + "/auth", "http://example.org"); + + chan.notificationCallbacks = new Requestor(16, 2); + listener.expectedCode = 200; // OK + chan.asyncOpen2(listener); + + do_test_pending(); +} + function test_returnfalse2() { - var chan = makeChan(URL + "/auth"); + var chan = makeChan(URL + "/auth", URL); chan.notificationCallbacks = new Requestor(FLAG_RETURN_FALSE, 2); listener.expectedCode = 401; // Unauthorized @@ -353,7 +394,7 @@ function test_returnfalse2() { } function test_wrongpw2() { - var chan = makeChan(URL + "/auth"); + var chan = makeChan(URL + "/auth", URL); chan.notificationCallbacks = new Requestor(FLAG_WRONG_PASSWORD, 2); listener.expectedCode = 200; // OK @@ -363,7 +404,7 @@ function test_wrongpw2() { } function test_prompt2() { - var chan = makeChan(URL + "/auth"); + var chan = makeChan(URL + "/auth", URL); chan.notificationCallbacks = new Requestor(0, 2); listener.expectedCode = 200; // OK @@ -373,7 +414,7 @@ function test_prompt2() { } function test_ntlm() { - var chan = makeChan(URL + "/auth/ntlm/simple"); + var chan = makeChan(URL + "/auth/ntlm/simple", URL); chan.notificationCallbacks = new Requestor(FLAG_RETURN_FALSE, 2); listener.expectedCode = 401; // Unauthorized @@ -383,7 +424,7 @@ function test_ntlm() { } function test_basicrealm() { - var chan = makeChan(URL + "/auth/realm"); + var chan = makeChan(URL + "/auth/realm", URL); chan.notificationCallbacks = new RealmTestRequestor(); listener.expectedCode = 401; // Unauthorized @@ -393,7 +434,7 @@ function test_basicrealm() { } function test_digest_noauth() { - var chan = makeChan(URL + "/auth/digest"); + var chan = makeChan(URL + "/auth/digest", URL); //chan.notificationCallbacks = new Requestor(FLAG_RETURN_FALSE, 2); listener.expectedCode = 401; // Unauthorized @@ -403,7 +444,7 @@ function test_digest_noauth() { } function test_digest() { - var chan = makeChan(URL + "/auth/digest"); + var chan = makeChan(URL + "/auth/digest", URL); chan.notificationCallbacks = new Requestor(0, 2); listener.expectedCode = 200; // OK @@ -413,7 +454,7 @@ function test_digest() { } function test_digest_bogus_user() { - var chan = makeChan(URL + "/auth/digest"); + var chan = makeChan(URL + "/auth/digest", URL); chan.notificationCallbacks = new Requestor(FLAG_BOGUS_USER, 2); listener.expectedCode = 401; // unauthorized chan.asyncOpen2(listener); @@ -2016,7 +2057,7 @@ function largeDomain(metadata, response) { } function test_large_realm() { - var chan = makeChan(URL + "/largeRealm"); + var chan = makeChan(URL + "/largeRealm", URL); listener.expectedCode = 401; // Unauthorized chan.asyncOpen2(listener); @@ -2025,7 +2066,7 @@ function test_large_realm() { } function test_large_domain() { - var chan = makeChan(URL + "/largeDomain "); + var chan = makeChan(URL + "/largeDomain", URL); listener.expectedCode = 401; // Unauthorized chan.asyncOpen2(listener); diff --git a/toolkit/components/passwordmgr/test/mochitest/test_prompt.html b/toolkit/components/passwordmgr/test/mochitest/test_prompt.html index ccc3584375d4..49ad9fd6aff2 100644 --- a/toolkit/components/passwordmgr/test/mochitest/test_prompt.html +++ b/toolkit/components/passwordmgr/test/mochitest/test_prompt.html @@ -916,7 +916,7 @@ add_task(function* runTests() { // ===== test 500 ===== state = { - msg : "A username and password are being requested by http://example.com. The site says: “some realm”", + msg : "http://example.com is requesting your username and password.\n\nThe site says: “some realm”", title : "Authentication Required", textValue : "inuser", passValue : "inpass", @@ -949,7 +949,7 @@ add_task(function* runTests() { // ===== test 501 ===== state = { - msg : "A username and password are being requested by http://example.com. The site says: “some realm”", + msg : "http://example.com is requesting your username and password.\n\nThe site says: “some realm”", title : "Authentication Required", textValue : "outuser", passValue : "outpass", @@ -975,7 +975,7 @@ add_task(function* runTests() { // ===== test 502 ===== // test filling in password-only login state = { - msg : "A username and password are being requested by http://example.com. The site says: “http://example.com”", + msg : "http://example.com is requesting your username and password.\n\nThe site says: “http://example.com”", title : "Authentication Required", textValue : "", passValue : "examplepass", @@ -1008,7 +1008,7 @@ add_task(function* runTests() { // test filling in existing login (undetermined from multiple selection) // user2name/user2pass would also be valid to fill here. state = { - msg : "A username and password are being requested by http://example2.com. The site says: “http://example2.com”", + msg : "http://example2.com is requesting your username and password.\n\nThe site says: “http://example2.com”", title : "Authentication Required", textValue : "user1name", passValue : "user1pass", @@ -1041,7 +1041,7 @@ add_task(function* runTests() { // test filling in existing login (undetermined --> user1) // user2name/user2pass would also be valid to fill here. state = { - msg : "A username and password are being requested by http://example2.com. The site says: “http://example2.com”", + msg : "http://example2.com is requesting your username and password.\n\nThe site says: “http://example2.com”", title : "Authentication Required", textValue : "user1name", passValue : "user1pass", @@ -1077,7 +1077,7 @@ add_task(function* runTests() { // test filling in existing login (undetermined --> user2) // user2name/user2pass would also be valid to fill here. state = { - msg : "A username and password are being requested by http://example2.com. The site says: “http://example2.com”", + msg : "http://example2.com is requesting your username and password.\n\nThe site says: “http://example2.com”", title : "Authentication Required", textValue : "user1name", passValue : "user1pass", @@ -1114,7 +1114,7 @@ add_task(function* runTests() { // test changing a password (undetermined --> user2 w/ newpass) // user2name/user2pass would also be valid to fill here. state = { - msg : "A username and password are being requested by http://example2.com. The site says: “http://example2.com”", + msg : "http://example2.com is requesting your username and password.\n\nThe site says: “http://example2.com”", title : "Authentication Required", textValue : "user1name", passValue : "user1pass", @@ -1151,7 +1151,7 @@ add_task(function* runTests() { // test changing a password (undetermined --> user2 w/ origpass) // user2name/user2pass would also be valid to fill here. state = { - msg : "A username and password are being requested by http://example2.com. The site says: “http://example2.com”", + msg : "http://example2.com is requesting your username and password.\n\nThe site says: “http://example2.com”", title : "Authentication Required", textValue : "user1name", passValue : "user1pass", @@ -1187,7 +1187,7 @@ add_task(function* runTests() { // ===== test 508 ===== // test proxy login (default = no autologin), make sure it prompts. state = { - msg : "The proxy moz-proxy://127.0.0.1:8888 is requesting a username and password. The site says: “Proxy Realm”", + msg : "The proxy moz-proxy://127.0.0.1:8888 is requesting a username and password.\n\nThe site says: “Proxy Realm”", title : "Authentication Required", textValue : "proxuser", passValue : "proxpass", @@ -1244,7 +1244,7 @@ add_task(function* runTests() { // ===== test 510 ===== // test proxy login (with autologin), ensure it prompts after a failed auth. state = { - msg : "The proxy moz-proxy://127.0.0.1:8888 is requesting a username and password. The site says: “Proxy Realm”", + msg : "The proxy moz-proxy://127.0.0.1:8888 is requesting a username and password.\n\nThe site says: “Proxy Realm”", title : "Authentication Required", textValue : "proxuser", passValue : "proxpass", @@ -1309,7 +1309,7 @@ add_task(function* runTests() { // ===== test 1000 ===== state = { - msg : "A username and password are being requested by http://mochi.test:8888. The site says: “mochitest”", + msg : "http://mochi.test:8888 is requesting your username and password.\n\nThe site says: “mochitest”", title : "Authentication Required", textValue : "mochiuser1", passValue : "mochipass1", @@ -1330,25 +1330,15 @@ add_task(function* runTests() { // The following tests are driven by iframe loads - function checkEchoedAuthInfo(expectedState) { - // The server echos back the HTTP auth info it received. - let username = iframe.contentDocument.getElementById("user").textContent; - let password = iframe.contentDocument.getElementById("pass").textContent; - let authok = iframe.contentDocument.getElementById("ok").textContent; - - is(authok, "PASS", "Checking for successful authentication"); - is(username, expectedState.user, "Checking for echoed username"); - is(password, expectedState.pass, "Checking for echoed password"); - } - var iframeLoaded = onloadPromiseFor("iframe"); iframe.src = "authenticate.sjs?user=mochiuser1&pass=mochipass1"; yield promptDone; yield iframeLoaded; - checkEchoedAuthInfo({user: "mochiuser1", pass: "mochipass1"}); + checkEchoedAuthInfo({user: "mochiuser1", pass: "mochipass1"}, + iframe.contentDocument); state = { - msg : "A username and password are being requested by http://mochi.test:8888. The site says: “mochitest2”", + msg : "http://mochi.test:8888 is requesting your username and password.\n\nThe site says: “mochitest2”", title : "Authentication Required", textValue : "mochiuser2", passValue : "mochipass2", @@ -1373,7 +1363,8 @@ add_task(function* runTests() { iframe.src = "authenticate.sjs?user=mochiuser2&pass=mochipass2&realm=mochitest2"; yield promptDone; yield iframeLoaded; - checkEchoedAuthInfo({user: "mochiuser2", pass: "mochipass2"}); + checkEchoedAuthInfo({user: "mochiuser2", pass: "mochipass2"}, + iframe.contentDocument); // Now make a load that requests the realm from test 1000. It was // already provided there, so auth will *not* be prompted for -- the @@ -1381,13 +1372,14 @@ add_task(function* runTests() { iframeLoaded = onloadPromiseFor("iframe"); iframe.src = "authenticate.sjs?user=mochiuser1&pass=mochipass1"; yield iframeLoaded; - checkEchoedAuthInfo({user: "mochiuser1", pass: "mochipass1"}); + checkEchoedAuthInfo({user: "mochiuser1", pass: "mochipass1"}, + iframe.contentDocument); // Same realm we've already authenticated to, but with a different // expected password (to trigger an auth prompt, and change-password // popup notification). state = { - msg : "A username and password are being requested by http://mochi.test:8888. The site says: “mochitest”", + msg : "http://mochi.test:8888 is requesting your username and password.\n\nThe site says: “mochitest”", title : "Authentication Required", textValue : "mochiuser1", passValue : "mochipass1", @@ -1410,7 +1402,8 @@ add_task(function* runTests() { iframe.src = "authenticate.sjs?user=mochiuser1&pass=mochipass1-new"; yield promptDone; yield iframeLoaded; - checkEchoedAuthInfo({user: "mochiuser1", pass: "mochipass1-new"}); + checkEchoedAuthInfo({user: "mochiuser1", pass: "mochipass1-new"}, + iframe.contentDocument); // Housekeeping: change it back var pwchanged = new Promise(resolve => { @@ -1436,7 +1429,7 @@ add_task(function* runTests() { // to (but have an existing saved login for, so that we'll trigger // a change-password popup notification. state = { - msg : "A username and password are being requested by http://mochi.test:8888. The site says: “mochitest3”", + msg : "http://mochi.test:8888 is requesting your username and password.\n\nThe site says: “mochitest3”", title : "Authentication Required", textValue : "mochiuser3", passValue : "mochipass3-old", @@ -1459,7 +1452,8 @@ add_task(function* runTests() { iframe.src = "authenticate.sjs?user=mochiuser3&pass=mochipass3-new&realm=mochitest3"; yield promptDone; yield iframeLoaded; - checkEchoedAuthInfo({user: "mochiuser3", pass: "mochipass3-new"}); + checkEchoedAuthInfo({user: "mochiuser3", pass: "mochipass3-new"}, + iframe.contentDocument); // Housekeeping: change it back to the original login4. Actually, // just delete it and we'll re-add it as the next test. @@ -1490,7 +1484,7 @@ add_task(function* runTests() { ok(true, "authMgr cleared cached auth"); state = { - msg : "A username and password are being requested by http://mochi.test:8888. The site says: “mochitest3”", + msg : "http://mochi.test:8888 is requesting your username and password.\n\nThe site says: “mochitest3”", title : "Authentication Required", textValue : "", passValue : "", @@ -1516,7 +1510,8 @@ add_task(function* runTests() { iframe.src = "authenticate.sjs?user=mochiuser3&pass=mochipass3-old&realm=mochitest3"; yield promptDone; yield iframeLoaded; - checkEchoedAuthInfo({user: "mochiuser3", pass: "mochipass3-old"}); + checkEchoedAuthInfo({user: "mochiuser3", pass: "mochipass3-old"}, + iframe.contentDocument); var pwsaved = new Promise(resolve => { function finishIt() { diff --git a/toolkit/components/prompts/content/commonDialog.js b/toolkit/components/prompts/content/commonDialog.js index 70b373d1f251..ef4686654214 100644 --- a/toolkit/components/prompts/content/commonDialog.js +++ b/toolkit/components/prompts/content/commonDialog.js @@ -50,6 +50,8 @@ function commonDialogOnLoad() { Dialog = new CommonDialog(args, ui); Dialog.onLoad(dialog); + // resize the window to the content + window.sizeToContent(); window.getAttention(); } diff --git a/toolkit/components/prompts/src/nsPrompter.js b/toolkit/components/prompts/src/nsPrompter.js index 2fa1b19d2767..efd004f678c6 100644 --- a/toolkit/components/prompts/src/nsPrompter.js +++ b/toolkit/components/prompts/src/nsPrompter.js @@ -255,6 +255,8 @@ var PromptUtilsTemp = { makeAuthMessage : function (channel, authInfo) { let isProxy = (authInfo.flags & Ci.nsIAuthInformation.AUTH_PROXY); let isPassOnly = (authInfo.flags & Ci.nsIAuthInformation.ONLY_PASSWORD); + let isCrossOrig = (authInfo.flags & + Ci.nsIAuthInformation.CROSS_ORIGIN_SUB_RESOURCE); let username = authInfo.username; let [displayHost, realm] = this.getAuthTarget(channel, authInfo); @@ -271,14 +273,17 @@ var PromptUtilsTemp = { } let text; - if (isProxy) - text = PromptUtils.getLocalizedString("EnterLoginForProxy", [realm, displayHost]); - else if (isPassOnly) + if (isProxy) { + text = PromptUtils.getLocalizedString("EnterLoginForProxy2", [realm, displayHost]); + } else if (isPassOnly) { text = PromptUtils.getLocalizedString("EnterPasswordFor", [username, displayHost]); - else if (!realm) - text = PromptUtils.getLocalizedString("EnterUserPasswordFor", [displayHost]); - else - text = PromptUtils.getLocalizedString("EnterLoginForRealm", [realm, displayHost]); + } else if (isCrossOrig) { + text = PromptUtils.getLocalizedString("EnterUserPasswordForCrossOrigin", [displayHost]); + } else if (!realm) { + text = PromptUtils.getLocalizedString("EnterUserPasswordFor2", [displayHost]); + } else { + text = PromptUtils.getLocalizedString("EnterLoginForRealm2", [realm, displayHost]); + } return text; }, diff --git a/toolkit/components/prompts/test/mochitest.ini b/toolkit/components/prompts/test/mochitest.ini index c711088aa8ef..86f09096c7c8 100644 --- a/toolkit/components/prompts/test/mochitest.ini +++ b/toolkit/components/prompts/test/mochitest.ini @@ -1,6 +1,7 @@ [DEFAULT] skip-if = buildapp == 'mulet' || buildapp == 'b2g' support-files = + ../../passwordmgr/test/authenticate.sjs bug619644_inner.html bug625187_iframe.html prompt_common.js @@ -9,7 +10,8 @@ support-files = [test_bug619644.html] [test_bug620145.html] skip-if = toolkit == 'android' #TIMED_OUT -[test_bug625187.html] +[test_subresources_prompts.html] +skip-if = toolkit == 'android' [test_dom_prompts.html] skip-if = toolkit == 'android' #android: bug 1267092 [test_modal_prompts.html] diff --git a/toolkit/components/prompts/test/prompt_common.js b/toolkit/components/prompts/test/prompt_common.js index 2c502cb98ce8..82dfad01b87a 100644 --- a/toolkit/components/prompts/test/prompt_common.js +++ b/toolkit/components/prompts/test/prompt_common.js @@ -85,3 +85,14 @@ function checkPromptState(promptState, expectedState) { is(promptState.focused, expectedState.focused, "Checking focused element"); } } + +function checkEchoedAuthInfo(expectedState, doc) { + // The server echos back the HTTP auth info it received. + let username = doc.getElementById("user").textContent; + let password = doc.getElementById("pass").textContent; + let authok = doc.getElementById("ok").textContent; + + is(authok, "PASS", "Checking for successful authentication"); + is(username, expectedState.user, "Checking for echoed username"); + is(password, expectedState.pass, "Checking for echoed password"); +} diff --git a/toolkit/components/prompts/test/test_modal_prompts.html b/toolkit/components/prompts/test/test_modal_prompts.html index 6f3bfec75673..98a7e34271d7 100644 --- a/toolkit/components/prompts/test/test_modal_prompts.html +++ b/toolkit/components/prompts/test/test_modal_prompts.html @@ -982,7 +982,7 @@ function* runTests() { // (promptAuth is only accessible from the prompt service) info("Starting test: promptAuth with empty realm"); state = { - msg : 'Enter username and password for http://example.com', + msg : 'http://example.com is requesting your username and password.', title : "TestTitle", iconClass : "authentication-icon question-icon", titleHidden : true, @@ -1020,7 +1020,7 @@ function* runTests() { // (promptAuth is only accessible from the prompt service) info("Starting test: promptAuth with long realm"); state = { - msg : 'A username and password are being requested by http://example.com. The site ' + + msg : 'http://example.com is requesting your username and password.\n\nThe site ' + 'says: \u201cabcdefghi abcdefghi abcdefghi abcdefghi abcdefghi abcdefghi abcdefghi ' + 'abcdefghi abcdefghi abcdefghi abcdefghi abcdefghi abcdefghi abcdefghi ' + 'abcdefghi \u2026\u201d', @@ -1061,6 +1061,94 @@ function* runTests() { yield promptDone; } + + info("Starting test: promptAuth for a cross-origin and a empty realm"); + authinfo = { + username : "", + password : "", + domain : "", + flags : Ci. nsIAuthInformation.AUTH_HOST | + Ci.nsIAuthInformation.CROSS_ORIGIN_SUB_RESOURCE, + authenticationScheme : "basic", + realm : "" + } + state = { + msg : 'http://example.com is requesting your username and password.\n\n' + + 'WARNING: Your password will not be sent to the website you are currently visiting!', + title : "TestTitle", + iconClass : "authentication-icon question-icon", + titleHidden : true, + textHidden : false, + passHidden : false, + checkHidden : false, + textValue : "", + passValue : "", + checkMsg : "Check me out!", + checked : false, + focused : "textField", + defButton : "button0", + }; + action = { + buttonClick : "ok", + setCheckbox : false, + textField : "username", + passField : "password", + }; + if (usePromptService) { + promptDone = handlePrompt(state, action); + checkVal.value = false; + isOK = prompter.promptAuth(window, channel, level, authinfo, "Check me out!", checkVal); + is(isOK, true, "checked expected retval"); + is(authinfo.username, "username", "checking filled username"); + is(authinfo.password, "password", "checking filled password"); + is(checkVal.value, true, "expected checkbox setting"); + + yield promptDone; + } + + info("Starting test: promptAuth for a cross-origin with realm"); + authinfo = { + username : "", + password : "", + domain : "", + flags : Ci. nsIAuthInformation.AUTH_HOST | Ci.nsIAuthInformation.CROSS_ORIGIN_SUB_RESOURCE, + authenticationScheme : "basic", + realm : "Something!!!" + } + state = { + msg : 'http://example.com is requesting your username and password.\n\n' + + 'WARNING: Your password will not be sent to the website you are currently visiting!', + title : "TestTitle", + iconClass : "authentication-icon question-icon", + titleHidden : true, + textHidden : false, + passHidden : false, + checkHidden : false, + textValue : "", + passValue : "", + checkMsg : "Check me out!", + checked : false, + focused : "textField", + defButton : "button0", + }; + action = { + buttonClick : "ok", + setCheckbox : false, + textField : "username", + passField : "password", + }; + if (usePromptService) { + promptDone = handlePrompt(state, action); + + checkVal.value = false; + isOK = prompter.promptAuth(window, channel, level, authinfo, "Check me out!", checkVal); + is(isOK, true, "checked expected retval"); + is(authinfo.username, "username", "checking filled username"); + is(authinfo.password, "password", "checking filled password"); + is(checkVal.value, true, "expected checkbox setting"); + + yield promptDone; + } } let usePromptService; diff --git a/toolkit/components/prompts/test/test_bug625187.html b/toolkit/components/prompts/test/test_subresources_prompts.html similarity index 53% rename from toolkit/components/prompts/test/test_bug625187.html rename to toolkit/components/prompts/test/test_subresources_prompts.html index 212e39334dc2..b250173554ca 100644 --- a/toolkit/components/prompts/test/test_bug625187.html +++ b/toolkit/components/prompts/test/test_subresources_prompts.html @@ -1,6 +1,6 @@ - Test for Bug 625187 + Test subresources prompts (Bug 625187 and bug 1230462) @@ -17,6 +17,7 @@ Mozilla Bug 625187 +Mozilla Bug 1230462

@@ -24,11 +25,14 @@ + +