Bug 1230462 - Change the authentiation dialog message. r=mayhemer,dolske,margaret,tanvi
☠☠ backed out by b9213f375a3f ☠ ☠
authorDragana Damjanovic <dd.mozilla@gmail.com>
Fri, 03 Jun 2016 09:09:00 +0200
changeset 325021 490d3460a197ab1d468250b5ca661741868a4337
parent 325020 c5b4391bfdd4b74afd189e1894912f0cb5023074
child 325022 7e9f778585288a52dbd6333b77ed817df6c97177
push id9671
push userraliiev@mozilla.com
push dateMon, 06 Jun 2016 20:27:52 +0000
treeherdermozilla-aurora@cea65ca3d0bd [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersmayhemer, dolske, margaret, tanvi
bugs1230462
milestone49.0a1
Bug 1230462 - Change the authentiation dialog message. r=mayhemer,dolske,margaret,tanvi
extensions/gio/nsGIOProtocolHandler.cpp
mobile/android/components/PromptService.js
netwerk/base/nsIAuthInformation.idl
netwerk/protocol/http/nsHttpChannelAuthProvider.cpp
netwerk/protocol/http/nsHttpChannelAuthProvider.h
netwerk/test/unit/test_authentication.js
toolkit/components/passwordmgr/test/mochitest/test_prompt.html
toolkit/components/prompts/content/commonDialog.js
toolkit/components/prompts/src/nsPrompter.js
toolkit/components/prompts/test/mochitest.ini
toolkit/components/prompts/test/prompt_common.js
toolkit/components/prompts/test/test_bug625187.html
toolkit/components/prompts/test/test_modal_prompts.html
toolkit/components/prompts/test/test_subresources_prompts.html
toolkit/components/telemetry/Histograms.json
toolkit/locales/en-US/chrome/global/commonDialogs.properties
--- a/extensions/gio/nsGIOProtocolHandler.cpp
+++ b/extensions/gio/nsGIOProtocolHandler.cpp
@@ -821,21 +821,21 @@ mount_operation_ask_password (GMountOper
     return;
   }
   nsAutoString nsmessage;
 
   if (flags & G_ASK_PASSWORD_NEED_PASSWORD) {
     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 {
       NS_ConvertUTF8toUTF16 userName(default_user);
       const char16_t *strings[] = { userName.get(), dispHost.get() };
       bundle->FormatStringFromName(MOZ_UTF16("EnterPasswordFor"),
                                    strings, 2, getter_Copies(nsmessage));
     }
--- a/mobile/android/components/PromptService.js
+++ b/mobile/android/components/PromptService.js
@@ -671,40 +671,45 @@ var PromptUtils = {
 
     this.pwmgr.modifyLogin(aLogin, propBag);
   },
 
   // JS port of http://mxr.mozilla.org/mozilla-central/source/embedding/components/windowwatcher/nsPrompt.cpp#388
   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);
 
     // Suppress "the site says: $realm" when we synthesized a missing realm.
     if (!aAuthInfo.realm && !isProxy)
     realm = "";
 
     // Trim obnoxiously long realms.
     if (realm.length > 150) {
       realm = realm.substring(0, 150);
       // Append "..." (or localized equivalent).
       realm += this.ellipsis;
     }
 
     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;
   },
 
   // JS port of http://mxr.mozilla.org/mozilla-central/source/embedding/components/windowwatcher/nsPromptUtils.h#89
   getAuthHostPort: function pu_getAuthHostPort(aChannel, aAuthInfo) {
     let uri = aChannel.URI;
     let res = { host: null, port: -1 };
--- a/netwerk/base/nsIAuthInformation.idl
+++ b/netwerk/base/nsIAuthInformation.idl
@@ -49,16 +49,22 @@ interface nsIAuthInformation : nsISuppor
   /**
    * We have already tried to log in for this channel
    * (with auth values from a previous promptAuth call),
    * but it failed, so we now ask the user to provide a new, correct login.
    *
    * @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;
   /* @} */
 
   /**
    * Flags describing this dialog. A bitwise OR of the flag values
    * above.
    *
    * It is possible that neither #AUTH_HOST nor #AUTH_PROXY are set.
    *
--- a/netwerk/protocol/http/nsHttpChannelAuthProvider.cpp
+++ b/netwerk/protocol/http/nsHttpChannelAuthProvider.cpp
@@ -35,16 +35,17 @@ namespace net {
 
 #define SUBRESOURCE_AUTH_DIALOG_DISALLOW_ALL 0
 #define SUBRESOURCE_AUTH_DIALOG_DISALLOW_CROSS_ORIGIN 1
 #define SUBRESOURCE_AUTH_DIALOG_ALLOW_ALL 2
 
 #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
 #define HTTP_AUTH_DIGEST_INSECURE 2
 #define HTTP_AUTH_DIGEST_SECURE 3
 #define HTTP_AUTH_NTLM_INSECURE 4
 #define HTTP_AUTH_NTLM_SECURE 5
 #define HTTP_AUTH_NEGOTIATE_INSECURE 6
@@ -67,16 +68,17 @@ nsHttpChannelAuthProvider::nsHttpChannel
     : mAuthChannel(nullptr)
     , mIsPrivate(false)
     , mProxyAuthContinuationState(nullptr)
     , mAuthContinuationState(nullptr)
     , mProxyAuth(false)
     , mTriedProxyAuth(false)
     , mTriedHostAuth(false)
     , mSuppressDefensiveAuth(false)
+    , mCrossOrigin(false)
     , mHttpHandler(gHttpHandler)
 {
 }
 
 nsHttpChannelAuthProvider::~nsHttpChannelAuthProvider()
 {
     MOZ_ASSERT(!mAuthChannel, "Disconnect wasn't called");
 }
@@ -790,18 +792,22 @@ nsHttpChannelAuthProvider::GetCredential
                   UsingSSL() ? HTTP_AUTH_NEGOTIATE_SECURE : HTTP_AUTH_NEGOTIATE_INSECURE);
               }
             }
 
             // Depending on the pref setting, the authentication dialog may be
             // 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
             // their username and password for this domain.
             rv = PromptForIdentity(level, proxyAuth, realm.get(),
                                    authType, authFlags, *ident);
             if (NS_FAILED(rv)) return rv;
             identFromURI = false;
@@ -847,71 +853,82 @@ nsHttpChannelAuthProvider::BlockPrompt()
 {
     // Verify that it's ok to prompt for credentials here, per spec
     // http://xhr.spec.whatwg.org/#the-send%28%29-method
 
     nsCOMPtr<nsIHttpChannelInternal> chanInternal = do_QueryInterface(mAuthChannel);
     MOZ_ASSERT(chanInternal);
 
     if (chanInternal->GetBlockAuthPrompt()) {
+        LOG(("nsHttpChannelAuthProvider::BlockPrompt: Prompt is blocked "
+             "[this=%p channel=%p]\n", this, mAuthChannel));
         return true;
     }
 
     nsCOMPtr<nsIChannel> chan = do_QueryInterface(mAuthChannel);
     nsCOMPtr<nsILoadInfo> 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<nsIURI> topURI;
+            chanInternal->GetTopWindowURI(getter_AddRefs(topURI));
+
+            if (!topURI) {
+                // If we do not have topURI try the loadingPrincipal.
+                nsCOMPtr<nsIPrincipal> 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<nsIPrincipal> 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<nsIPrincipal> 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;
     default:
         // This is an invalid value.
         MOZ_ASSERT(false, "A non valid value!");
     }
     return false;
@@ -1095,16 +1112,20 @@ nsHttpChannelAuthProvider::PromptForIden
         if (mTriedHostAuth)
             promptFlags |= nsIAuthInformation::PREVIOUS_FAILED;
         mTriedHostAuth = true;
     }
 
     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,
                                   nsDependentCString(authType));
     if (!holder)
         return NS_ERROR_OUT_OF_MEMORY;
 
     nsCOMPtr<nsIChannel> channel(do_QueryInterface(mAuthChannel, &rv));
     if (NS_FAILED(rv)) return rv;
--- a/netwerk/protocol/http/nsHttpChannelAuthProvider.h
+++ b/netwerk/protocol/http/nsHttpChannelAuthProvider.h
@@ -149,16 +149,20 @@ private:
 
     // True when we need to authenticate to proxy, i.e. when we get 407
     // response. Used in OnAuthAvailable and OnAuthCancelled callbacks.
     uint32_t                          mProxyAuth                : 1;
     uint32_t                          mTriedProxyAuth           : 1;
     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<nsHttpHandler>           mHttpHandler;  // keep gHttpHandler alive
 
     // A variable holding the preference settings to whether to open HTTP
     // authentication credentials dialogs for sub-resources and cross-origin
     // sub-resources.
     static uint32_t                   sAuthAllowPref;
 };
 
--- a/netwerk/test/unit/test_authentication.js
+++ b/netwerk/test/unit/test_authentication.js
@@ -16,16 +16,17 @@ XPCOMUtils.defineLazyGetter(this, "URL",
 XPCOMUtils.defineLazyGetter(this, "PORT", function() {
   return httpserv.identity.primaryPort;
 });
 
 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;
 
 
 function AuthPrompt1(flags) {
   this.flags = flags;
 }
@@ -47,18 +48,25 @@ AuthPrompt1.prototype = {
     do_throw("unexpected prompt call");
   },
 
   promptUsernameAndPassword:
     function ap1_promptUP(title, text, realm, savePW, user, pw)
   {
     // 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)
       do_throw("Text must indicate the port");
     if (text.indexOf("-1") != -1)
       do_throw("Text must contain negative numbers");
 
     if (this.flags & FLAG_RETURN_FALSE)
@@ -117,20 +125,23 @@ AuthPrompt2.prototype = {
                         nsIAuthPrompt2.LEVEL_NONE;
     do_check_eq(expectedLevel, level);
 
     var expectedFlags = nsIAuthInformation.AUTH_HOST;
 
     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";
     do_check_eq(expectedScheme, authInfo.authenticationScheme);
 
     // No passwords in the URL -> nothing should be prefilled
     do_check_eq(authInfo.username, "");
     do_check_eq(authInfo.password, "");
@@ -269,22 +280,32 @@ var listener = {
       do_test_pending();
       httpserv.stop(do_test_finished);
     }
 
     do_test_finished();
   }
 };
 
-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];
 
 var current_test = 0;
 
 var httpserv = null;
 
@@ -299,126 +320,146 @@ function run_test() {
   httpserv.registerPathHandler("/largeDomain", largeDomain);
 
   httpserv.start(-1);
 
   tests[0]();
 }
 
 function test_noauth() {
-  var chan = makeChan(URL + "/auth");
+  var chan = makeChan(URL + "/auth", URL);
 
   listener.expectedCode = 401; // Unauthorized
   chan.asyncOpen2(listener);
 
   do_test_pending();
 }
 
 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
   chan.asyncOpen2(listener);
 
   do_test_pending();
 }
 
 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
   chan.asyncOpen2(listener);
 
   do_test_pending();
 }
 
 function test_prompt1() {
-  var chan = makeChan(URL + "/auth");
+  var chan = makeChan(URL + "/auth", URL);
 
   chan.notificationCallbacks = new Requestor(0, 1);
   listener.expectedCode = 200; // OK
   chan.asyncOpen2(listener);
 
   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
   chan.asyncOpen2(listener);
 
   do_test_pending();
 }
 
 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
   chan.asyncOpen2(listener);
 
   do_test_pending();
 }
 
 function test_prompt2() {
-  var chan = makeChan(URL + "/auth");
+  var chan = makeChan(URL + "/auth", URL);
 
   chan.notificationCallbacks = new Requestor(0, 2);
   listener.expectedCode = 200; // OK
   chan.asyncOpen2(listener);
 
   do_test_pending();
 }
 
 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
   chan.asyncOpen2(listener);
 
   do_test_pending();
 }
 
 function test_basicrealm() {
-  var chan = makeChan(URL + "/auth/realm");
+  var chan = makeChan(URL + "/auth/realm", URL);
 
   chan.notificationCallbacks = new RealmTestRequestor();
   listener.expectedCode = 401; // Unauthorized
   chan.asyncOpen2(listener);
 
   do_test_pending();
 }
 
 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
   chan.asyncOpen2(listener);
 
   do_test_pending();
 }
 
 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
   chan.asyncOpen2(listener);
 
   do_test_pending();
 }
 
 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);
 
   do_test_pending();
 }
 
 // PATH HANDLERS
@@ -2011,24 +2052,24 @@ function largeDomain(metadata, response)
 		     "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa" +
 		     '"');
 
   body = "need to authenticate";
   response.bodyOutputStream.write(body, body.length);
 }
 
 function test_large_realm() {
-  var chan = makeChan(URL + "/largeRealm");
+  var chan = makeChan(URL + "/largeRealm", URL);
 
   listener.expectedCode = 401; // Unauthorized
   chan.asyncOpen2(listener);
 
   do_test_pending();
 }
 
 function test_large_domain() {
-  var chan = makeChan(URL + "/largeDomain ");
+  var chan = makeChan(URL + "/largeDomain", URL);
 
   listener.expectedCode = 401; // Unauthorized
   chan.asyncOpen2(listener);
 
   do_test_pending();
 }
--- a/toolkit/components/passwordmgr/test/mochitest/test_prompt.html
+++ b/toolkit/components/passwordmgr/test/mochitest/test_prompt.html
@@ -911,17 +911,17 @@ add_task(function* runTests() {
                                        null,      // aTriggeringPrincipal
                                        Ci.nsILoadInfo.SEC_ALLOW_CROSS_ORIGIN_DATA_IS_NULL,
                                        Ci.nsIContentPolicy.TYPE_OTHER);
 
   var level = Ci.nsIAuthPrompt2.LEVEL_NONE;
 
   // ===== 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",
     iconClass   : "authentication-icon question-icon",
     titleHidden : true,
     textHidden  : false,
     passHidden  : false,
     checkHidden : true,
@@ -944,17 +944,17 @@ add_task(function* runTests() {
   yield promptDone;
 
   ok(isOk, "Checking dialog return value (accept)");
   is(authinfo.username, "outuser", "Checking returned username");
   is(authinfo.password, "outpass", "Checking returned password");
 
   // ===== 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",
     iconClass   : "authentication-icon question-icon",
     titleHidden : true,
     textHidden  : false,
     passHidden  : false,
     checkHidden : true,
@@ -970,17 +970,17 @@ add_task(function* runTests() {
   isOk = prompter2.promptAuth(channel1, level, authinfo);
   yield promptDone;
 
   ok(!isOk, "Checking dialog return value (cancel)");
 
   // ===== 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",
     iconClass   : "authentication-icon question-icon",
     titleHidden : true,
     textHidden  : false,
     passHidden  : false,
     checkHidden : true,
@@ -1003,17 +1003,17 @@ add_task(function* runTests() {
   ok(isOk, "Checking dialog return value (accept)");
   is(authinfo.username, "", "Checking returned username");
   is(authinfo.password, "examplepass", "Checking returned password");
 
   // ===== test 503 =====
   // 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",
     iconClass   : "authentication-icon question-icon",
     titleHidden : true,
     textHidden  : false,
     passHidden  : false,
     checkHidden : true,
@@ -1036,17 +1036,17 @@ add_task(function* runTests() {
   ok(isOk, "Checking dialog return value (accept)");
   ok(authinfo.username == "user1name" || authinfo.username == "user2name", "Checking returned username");
   ok(authinfo.password == "user1pass" || authinfo.password == "user2pass", "Checking returned password");
 
   // ===== test 504 =====
   // 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",
     iconClass   : "authentication-icon question-icon",
     titleHidden : true,
     textHidden  : false,
     passHidden  : false,
     checkHidden : true,
@@ -1072,17 +1072,17 @@ add_task(function* runTests() {
   ok(isOk, "Checking dialog return value (accept)");
   is(authinfo.username, "user1name", "Checking returned username");
   is(authinfo.password, "user1pass", "Checking returned password");
 
   // ===== test 505 =====
   // 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",
     iconClass   : "authentication-icon question-icon",
     titleHidden : true,
     textHidden  : false,
     passHidden  : false,
     checkHidden : true,
@@ -1109,17 +1109,17 @@ add_task(function* runTests() {
   ok(isOk, "Checking dialog return value (accept)");
   is(authinfo.username, "user2name", "Checking returned username");
   is(authinfo.password, "user2pass", "Checking returned password");
 
   // ===== test 506 =====
   // 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",
     iconClass   : "authentication-icon question-icon",
     titleHidden : true,
     textHidden  : false,
     passHidden  : false,
     checkHidden : true,
@@ -1146,17 +1146,17 @@ add_task(function* runTests() {
   ok(isOk, "Checking dialog return value (accept)");
   is(authinfo.username, "user2name", "Checking returned username");
   is(authinfo.password, "NEWuser2pass", "Checking returned password");
 
   // ===== test 507 =====
   // 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",
     iconClass   : "authentication-icon question-icon",
     titleHidden : true,
     textHidden  : false,
     passHidden  : false,
     checkHidden : true,
@@ -1182,17 +1182,17 @@ add_task(function* runTests() {
 
   ok(isOk, "Checking dialog return value (accept)");
   is(authinfo.username, "user2name", "Checking returned username");
   is(authinfo.password, "user2pass", "Checking returned password");
 
   // ===== 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",
     iconClass   : "authentication-icon question-icon",
     titleHidden : true,
     textHidden  : false,
     passHidden  : false,
     checkHidden : true,
@@ -1239,17 +1239,17 @@ add_task(function* runTests() {
   ok(isOk, "Checking dialog return value (accept)");
   isnot(time1, time2, "Checking that timeLastUsed was updated");
   is(proxyAuthinfo.username, "proxuser", "Checking returned username");
   is(proxyAuthinfo.password, "proxpass", "Checking returned password");
 
   // ===== 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",
     iconClass   : "authentication-icon question-icon",
     titleHidden : true,
     textHidden  : false,
     passHidden  : false,
     checkHidden : true,
@@ -1304,17 +1304,17 @@ add_task(function* runTests() {
   // clear plain HTTP auth sessions before the test, to allow
   // running them more than once.
   var authMgr = Cc['@mozilla.org/network/http-auth-manager;1'].
                 getService(Ci.nsIHttpAuthManager);
   authMgr.clearAll();
 
   // ===== 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",
     iconClass   : "authentication-icon question-icon",
     titleHidden : true,
     textHidden  : false,
     passHidden  : false,
     checkHidden : true,
@@ -1325,35 +1325,25 @@ add_task(function* runTests() {
   };
   action = {
     buttonClick : "ok",
   };
   promptDone = handlePrompt(state, action);
 
   // 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",
     iconClass   : "authentication-icon question-icon",
     titleHidden : true,
     textHidden  : false,
     passHidden  : false,
     checkHidden : true,
@@ -1368,31 +1358,33 @@ add_task(function* runTests() {
   promptDone = handlePrompt(state, action);
   // We've already authenticated to this host:port. For this next
   // request, the existing auth should be sent, we'll get a 401 reply,
   // and we should prompt for new auth.
   iframeLoaded = onloadPromiseFor("iframe");
   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
   // networking layer already knows it!
   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",
     iconClass   : "authentication-icon question-icon",
     titleHidden : true,
     textHidden  : false,
     passHidden  : false,
     checkHidden : true,
@@ -1405,17 +1397,18 @@ add_task(function* runTests() {
     buttonClick : "ok",
     passField   : "mochipass1-new",
   };
   promptDone = handlePrompt(state, action);
   iframeLoaded = onloadPromiseFor("iframe");
   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 => {
     function resetIt() {
       tmpLogin.init("http://mochi.test:8888", null, "mochitest",
                     "mochiuser1", "mochipass1-new", "", "");
       pwmgr.modifyLogin(tmpLogin, login3A);
       resolve(true);
@@ -1431,17 +1424,17 @@ add_task(function* runTests() {
   popup.remove();
 
   yield pwchanged;
 
   // Same as last test, but for a realm we haven't already authenticated
   // 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",
     iconClass   : "authentication-icon question-icon",
     titleHidden : true,
     textHidden  : false,
     passHidden  : false,
     checkHidden : true,
@@ -1454,17 +1447,18 @@ add_task(function* runTests() {
     buttonClick : "ok",
     passField   : "mochipass3-new",
   };
   promptDone = handlePrompt(state, action);
   iframeLoaded = onloadPromiseFor("iframe");
   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.
   pwchanged = new Promise(resolve => {
     function clearIt() {
       ok(true, "1004's clearIt() called.");
       try {
         tmpLogin.init("http://mochi.test:8888", null, "mochitest3",
@@ -1485,17 +1479,17 @@ add_task(function* runTests() {
   yield pwchanged;
 
 
   // Clear cached auth from this subtest, and avoid leaking due to bug 459620.
   authMgr.clearAll();
   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   : "",
     iconClass   : "authentication-icon question-icon",
     titleHidden : true,
     textHidden  : false,
     passHidden  : false,
     checkHidden : true,
@@ -1511,17 +1505,18 @@ add_task(function* runTests() {
   };
   // Trigger a new prompt, so we can test adding a new login.
   promptDone = handlePrompt(state, action);
 
   iframeLoaded = onloadPromiseFor("iframe");
   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() {
       finishTest();
       resolve(true);
     }
     addNotificationCallback(finishIt);
   });
--- a/toolkit/components/prompts/content/commonDialog.js
+++ b/toolkit/components/prompts/content/commonDialog.js
@@ -45,16 +45,18 @@ function commonDialogOnLoad() {
         focusTarget        : window,
     };
 
     // limit the dialog to the screen width
     document.getElementById("filler").maxWidth = screen.availWidth;
 
     Dialog = new CommonDialog(args, ui);
     Dialog.onLoad(dialog);
+    // resize the window to the content
+    window.sizeToContent();
     window.getAttention();
 }
 
 function commonDialogOnUnload() {
     // Convert args back into property bag
     for (let propName in args)
         propBag.setProperty(propName, args[propName]);
 }
--- a/toolkit/components/prompts/src/nsPrompter.js
+++ b/toolkit/components/prompts/src/nsPrompter.js
@@ -250,40 +250,45 @@ var PromptUtilsTemp = {
 
         return [hostname, realm];
     },
 
 
     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);
 
         // Suppress "the site says: $realm" when we synthesized a missing realm.
         if (!authInfo.realm && !isProxy)
             realm = "";
 
         // Trim obnoxiously long realms.
         if (realm.length > 150) {
             realm = realm.substring(0, 150);
             // Append "..." (or localized equivalent).
             realm += this.ellipsis;
         }
 
         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;
     },
 
     getTabModalPrompt : function (domWin) {
         var promptBox = null;
 
         try {
--- a/toolkit/components/prompts/test/mochitest.ini
+++ b/toolkit/components/prompts/test/mochitest.ini
@@ -1,18 +1,20 @@
 [DEFAULT]
 skip-if = buildapp == 'mulet' || buildapp == 'b2g'
 support-files =
+  ../../passwordmgr/test/authenticate.sjs
   bug619644_inner.html
   bug625187_iframe.html
   prompt_common.js
   chromeScript.js
 
 [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]
 skip-if = toolkit == 'android' || (os == 'linux' && (debug || asan)) #android: TIMED_OUT (For Linux : 950636)
 [test_modal_select.html]
 skip-if = toolkit == 'android' #android: TIMED_OUT
--- a/toolkit/components/prompts/test/prompt_common.js
+++ b/toolkit/components/prompts/test/prompt_common.js
@@ -80,8 +80,19 @@ function checkPromptState(promptState, e
     if (isLinux && (!promptState.focused || isE10S)) {
         todo(false, "Focus seems missing or wrong on Linux"); // bug 1265077
     } else if (isOSX && expectedState.focused && expectedState.focused.startsWith("button")) {
         is(promptState.focused, "infoBody", "buttons don't focus on OS X, but infoBody does instead");
     } else {
         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");
+}
--- a/toolkit/components/prompts/test/test_modal_prompts.html
+++ b/toolkit/components/prompts/test/test_modal_prompts.html
@@ -977,17 +977,17 @@ function* runTests() {
         realm : ""
     };
 
 
     // =====
     // (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,
         textHidden  : false,
         passHidden  : false,
         checkHidden : false,
         textValue   : "",
         passValue   : "",
@@ -1015,17 +1015,17 @@ function* runTests() {
         yield promptDone;
     }
 
 
     // =====
     // (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',
         title : "TestTitle",
         iconClass   : "authentication-icon question-icon",
         titleHidden : true,
         textHidden  : false,
         passHidden  : false,
@@ -1056,16 +1056,104 @@ function* runTests() {
         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 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;
 
 /*
  * Run the body of the 3 times:
  * - 1st pass: with window-modal prompts, using nsIPromptService
  * - 2nd pass: still window-modal, using nsIPrompt directly (via nsIPromptFactory)
rename from toolkit/components/prompts/test/test_bug625187.html
rename to toolkit/components/prompts/test/test_subresources_prompts.html
--- a/toolkit/components/prompts/test/test_bug625187.html
+++ b/toolkit/components/prompts/test/test_subresources_prompts.html
@@ -1,39 +1,43 @@
 <html>
 <head>
-  <title>Test for Bug 625187</title>
+  <title>Test subresources prompts (Bug 625187 and bug 1230462)</title>
   <script type="text/javascript" src="/MochiKit/MochiKit.js"></script>
   <script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
   <script type="text/javascript" src="/tests/SimpleTest/SpawnTask.js"></script>
   <script type="text/javascript" src="/tests/SimpleTest/EventUtils.js"></script>
   <script type="text/javascript" src="prompt_common.js"></script>
   <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css">
 <!--
    - Any copyright is dedicated to the Public Domain.
    - http://creativecommons.org/publicdomain/zero/1.0/
    -
    - Contributor(s):
    -   Mihai Sucan <mihai.sucan@gmail.com>
    -->
 </head>
 <body>
 <a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=625187">Mozilla Bug 625187</a>
+<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=1230462">Mozilla Bug 1230462</a>
 
 <p><button onclick="alert('hello world')">Button</button></p>
 
 <iframe id="iframe_diff_origin" src="http://example.com/tests/toolkit/components/prompts/test/bug625187_iframe.html"></iframe>
 
 <iframe id="iframe_same_origin" src="bug625187_iframe.html"></iframe>
 
+<iframe id="iframe_prompt"></iframe>
+
 <pre id="test"></pre>
 
 <script class="testbody" type="text/javascript">
 var iframe1Loaded = onloadPromiseFor("iframe_diff_origin");
 var iframe2Loaded = onloadPromiseFor("iframe_same_origin");
+var iframe_prompt = document.getElementById("iframe_prompt");
 
 add_task(function* runTest()
 {
   // This test depends on tab modal prompts being enabled.
   if (!isTabModal) {
     todo(false, "Test disabled when tab modal prompts are not enabled.");
     return;
   }
@@ -99,16 +103,106 @@ add_task(function* runTest()
   promptDone = handlePrompt(state, action);
 
   button = iframe.contentWindow.document.getElementById("btn2");
   dispatchMouseEvent(button, "click");
 
   yield promptDone;
 });
 
+add_task(function* runTestAuth()
+{
+  // Following tests chack prompt message for a cross-origin and not
+  // cross-origin subresources load
+
+  // Force parent to not look for tab-modal prompts, as they're not
+  // used for auth prompts.
+  isTabModal = false;
+
+  state = {
+    msg         : "http://mochi.test:8888 is requesting your username " +
+                  "and password.\n\nThe site says: “mochitest”",
+    title       : "Authentication Required",
+    textValue   : "",
+    passValue   : "",
+    iconClass   : "authentication-icon question-icon",
+    titleHidden : true,
+    textHidden  : false,
+    passHidden  : false,
+    checkHidden : true,
+    checkMsg    : "",
+    checked     : false,
+    focused     : "textField",
+    defButton   : "button0",
+  };
+
+  if (isE10S) {
+    state.checkHidden = false;
+    state.checkMsg = "Use Password Manager to remember this password."
+  }
+
+  action = {
+    buttonClick : "ok",
+    setCheckbox : false,
+    textField   : "mochiuser1",
+    passField   : "mochipass1",
+  };
+
+  promptDone = handlePrompt(state, action);
+
+  var iframe3Loaded = onloadPromiseFor("iframe_prompt");
+  iframe_prompt.src = "authenticate.sjs?user=mochiuser1&pass=mochipass1";
+  yield promptDone;
+  yield iframe3Loaded;
+  checkEchoedAuthInfo({user: "mochiuser1", pass: "mochipass1"},
+                      iframe_prompt.contentDocument);
+
+  // Cross-origin subresourse test.
+
+  // Force parent to not look for tab-modal prompts, as they're not used for auth prompts.
+  isTabModal =false;
+  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       : "Authentication Required",
+    textValue   : "",
+    passValue   : "",
+    iconClass   : "authentication-icon question-icon",
+    titleHidden : true,
+    textHidden  : false,
+    passHidden  : false,
+    checkHidden : true,
+    checkMsg    : "",
+    checked     : false,
+    focused     : "textField",
+    defButton   : "button0",
+  };
+
+  if (isE10S) {
+    state.checkHidden = false;
+    state.checkMsg = "Use Password Manager to remember this password."
+  }
+
+  action = {
+    buttonClick : "ok",
+    setCheckbox : false,
+    textField   : "mochiuser2",
+    passField   : "mochipass2",
+  };
+
+  promptDone = handlePrompt(state, action);
+
+  iframe3Loaded = onloadPromiseFor("iframe_prompt");
+  iframe_prompt.src = "http://example.com/tests/toolkit/components/prompts/test/authenticate.sjs?user=mochiuser2&pass=mochipass2&realm=mochitest";
+  yield promptDone;
+  yield iframe3Loaded;
+  checkEchoedAuthInfo({user: "mochiuser2", pass: "mochipass2"},
+                      SpecialPowers.wrap(iframe_prompt.contentWindow).document);
+});
+
 function dispatchMouseEvent(target, type)
 {
   var win = SpecialPowers.unwrap(target.ownerDocument.defaultView);
   var e = document.createEvent("MouseEvent");
   e.initEvent(type, false, false, win, 0, 1, 1, 1, 1,
               false, false, false, false, 0, null);
   var utils = SpecialPowers.getDOMWindowUtils(win);
   utils.dispatchDOMEventViaPresShell(SpecialPowers.unwrap(target), e, true);
--- a/toolkit/components/telemetry/Histograms.json
+++ b/toolkit/components/telemetry/Histograms.json
@@ -1422,18 +1422,18 @@
     "expires_in_version": "never",
     "kind": "enumerated",
     "n_values": 12,
     "description": "Whether the URL gets redirected?  (0=200, 1=301, 2=302, 3=304, 4=307, 5=308, 6=400, 7=401, 8=403, 9=404, 10=500, 11=other)"
   },
   "HTTP_AUTH_DIALOG_STATS": {
     "expires_in_version": "never",
     "kind": "enumerated",
-    "n_values": 3,
-    "description": "Stats about what kind of resource requested http authentication. (0=top-level doc, 1=same origin subresources 2=cross-origin subresources)"
+    "n_values": 4,
+    "description": "Stats about what kind of resource requested http authentication. (0=top-level doc, 1=same origin subresources, 2=cross-origin subresources, 3=xhr)"
   },
   "HTTP_AUTH_TYPE_STATS": {
     "alert_emails": ["rbarnes@mozilla.com"],
     "bug_numbers": [1266571],
     "expires_in_version": "52",
     "kind": "enumerated",
     "n_values": 8,
     "releaseChannelCollection": "opt-out",
--- a/toolkit/locales/en-US/chrome/global/commonDialogs.properties
+++ b/toolkit/locales/en-US/chrome/global/commonDialogs.properties
@@ -15,17 +15,18 @@ Yes=&Yes
 No=&No
 Save=&Save
 Revert=&Revert
 DontSave=Do&n’t Save
 ScriptDlgGenericHeading=[JavaScript Application]
 ScriptDlgHeading=The page at %S says:
 ScriptDialogLabel=Prevent this page from creating additional dialogs
 ScriptDialogPreventTitle=Confirm Dialog Preference
-# LOCALIZATION NOTE (EnterLoginForRealm, EnterLoginForProxy):
+# LOCALIZATION NOTE (EnterLoginForRealm2, EnterLoginForProxy2):
 # %1 is an untrusted string provided by a remote server. It could try to
 # take advantage of sentence structure in order to mislead the user (see
 # bug 244273). %1 should be integrated into the translated sentences as
 # little as possible. %2 is the url of the site being accessed.
-EnterLoginForRealm=A username and password are being requested by %2$S. The site says: “%1$S”
-EnterLoginForProxy=The proxy %2$S is requesting a username and password. The site says: “%1$S”
-EnterUserPasswordFor=Enter username and password for %1$S
+EnterLoginForRealm2=%2$S is requesting your username and password.\n\nThe site says: “%1$S”
+EnterLoginForProxy2=The proxy %2$S is requesting a username and password.\n\nThe site says: “%1$S”
+EnterUserPasswordFor2=%1$S is requesting your username and password.
+EnterUserPasswordForCrossOrigin=%1$S is requesting your username and password.\n\nWARNING: Your password will not be sent to the website you are currently visiting!
 EnterPasswordFor=Enter password for %1$S on %2$S