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 341558 490d3460a197ab1d468250b5ca661741868a4337
parent 341557 c5b4391bfdd4b74afd189e1894912f0cb5023074
child 341559 7e9f778585288a52dbd6333b77ed817df6c97177
push id1183
push userraliiev@mozilla.com
push dateMon, 05 Sep 2016 20:01:49 +0000
treeherdermozilla-release@3148731bed45 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersmayhemer, dolske, margaret, tanvi
bugs1230462
milestone49.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
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