Only allow non-mixed content protected subresources to ask for credentials
authordbates@webkit.org <dbates@webkit.org@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Fri, 27 Oct 2017 22:31:14 +0000 (22:31 +0000)
committerdbates@webkit.org <dbates@webkit.org@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Fri, 27 Oct 2017 22:31:14 +0000 (22:31 +0000)
https://bugs.webkit.org/show_bug.cgi?id=178919
<rdar://problem/35015245>

Reviewed by Alex Christensen.

Source/WebCore:

Only allow non-mixed content protected subresources to ask for credentials. It is not meaningful
to allow protected mixed-content subresources to ask for credentials.

Tests: http/tests/security/mixedContent/insecure-image-redirects-to-basic-auth-secure-image.html
       http/tests/security/mixedContent/insecure-script-redirects-to-basic-auth-secure-script.html
       http/tests/security/mixedContent/insecure-stylesheet-redirects-to-basic-auth-secure-stylesheet.html
       http/tests/security/mixedContent/secure-redirect-to-insecure-redirect-to-basic-auth-secure-image.https.html
       http/tests/security/mixedContent/secure-redirect-to-secure-redirect-to-basic-auth-insecure-image.https.html
       http/tests/security/mixedContent/secure-redirect-to-secure-redirect-to-basic-auth-secure-image.https.html

* loader/ResourceLoader.cpp:
(WebCore::ResourceLoader::ResourceLoader): Initialize m_canAskClientForCredentials based on the
specified resource loader options.
(WebCore::ResourceLoader::init): Update m_canAskClientForCredentials based on the URL of the initial
request.
(WebCore::ResourceLoader::isMixedContent const): Helper function to check if the specified URL
represents a mixed content resource.
(WebCore::ResourceLoader::willSendRequestInternal): If the original request or the redirect request
is mixed content then update state such that we will disallow asking for credentials.
(WebCore::ResourceLoader::isAllowedToAskUserForCredentials const): Modified to use m_canAskClientForCredentials
when determining whether the request is allowed to ask for credentials.
* loader/ResourceLoader.h:

Source/WebKit:

Only allow non-mixed content protected subresources to ask for credentials. It is not meaningful
to allow protected mixed-content subresources to ask for credentials.

* NetworkProcess/Downloads/PendingDownload.cpp:
(WebKit::PendingDownload::PendingDownload): Initialize m_isAllowedToAskUserForCredentials based on
the specified resource load parameters or NetworkLoad object.
* NetworkProcess/Downloads/PendingDownload.h: Add override for NetworkLoadClient::isAllowedToAskUserForCredentials().
* NetworkProcess/NetworkLoad.cpp:
(WebKit::NetworkLoad::isAllowedToAskUserForCredentials const): Added.
(WebKit::NetworkLoad::completeAuthenticationChallenge): Ask NetworkLoadClient whether the load is
allowed to prompt for credentials.
(WebKit::NetworkLoad::didReceiveAuthenticationChallenge): Ditto.
* NetworkProcess/NetworkLoad.h:
* NetworkProcess/NetworkLoadClient.h:
* NetworkProcess/NetworkResourceLoader.cpp:
(WebKit::NetworkResourceLoader::NetworkResourceLoader): Initialize m_isAllowedToAskUserForCredentials
based on the specified resource load parameters.
(WebKit::NetworkResourceLoader::willSendRedirectedRequest): We do not support prompting for credentials
for synchronous loads.
(WebKit::NetworkResourceLoader::continueWillSendRequest): Modified to take an argument as to whether the
load is allowed to ask the user for credentials and updates state.
* NetworkProcess/NetworkResourceLoader.h:
* NetworkProcess/NetworkResourceLoader.messages.in: Modified message ContinueWillSendRequest to take a
boolean as to whether the load is allowed to ask the user for credentials.
* NetworkProcess/PreconnectTask.h: Override NetworkLoadClient::isAllowedToAskUserForCredentials()
such that we never ask for credentials. This matches our current behavior.
* NetworkProcess/cache/NetworkCacheSpeculativeLoad.h: Ditto.
* WebProcess/Network/WebResourceLoader.cpp:
(WebKit::WebResourceLoader::willSendRequest): Query ResourceLoader as to whether the load is allowed to
ask the user for credentials and pass this state to NetworkResourceLoader.

LayoutTests:

* http/tests/security/mixedContent/insecure-download-redirects-to-basic-auth-secure-download.https-expected.txt: Added.
* http/tests/security/mixedContent/insecure-download-redirects-to-basic-auth-secure-download.https.html: Added.
* http/tests/security/mixedContent/insecure-image-redirects-to-basic-auth-secure-image-expected.txt: Added.
* http/tests/security/mixedContent/insecure-image-redirects-to-basic-auth-secure-image.html: Added.
* http/tests/security/mixedContent/insecure-script-redirects-to-basic-auth-secure-script-expected.https.txt: Added.
* http/tests/security/mixedContent/insecure-script-redirects-to-basic-auth-secure-script-expected.txt: Added.
* http/tests/security/mixedContent/insecure-script-redirects-to-basic-auth-secure-script.html: Added.
* http/tests/security/mixedContent/insecure-stylesheet-redirects-to-basic-auth-secure-stylesheet-expected.txt: Added.
* http/tests/security/mixedContent/insecure-stylesheet-redirects-to-basic-auth-secure-stylesheet.html: Added.
* http/tests/security/mixedContent/resources/frame-with-insecure-image-redirects-to-basic-auth-secure-image.html: Added.
* http/tests/security/mixedContent/resources/frame-with-insecure-script-redirects-to-basic-auth-secure-script.html: Added.
* http/tests/security/mixedContent/resources/frame-with-insecure-stylesheet-redirects-to-basic-auth-secure-stylesheet.html: Added.
* http/tests/security/mixedContent/resources/frame-with-programmatically-added-insecure-image-redirects-to-basic-auth-secure-image.html: Added.
* http/tests/security/mixedContent/resources/subresource/protected-image.php: Added.
* http/tests/security/mixedContent/resources/subresource/protected-pdf.php: Added.
* http/tests/security/mixedContent/resources/subresource/protected-script.php: Added.
* http/tests/security/mixedContent/resources/subresource/protected-stylesheet.php: Added.
* http/tests/security/mixedContent/secure-redirect-to-insecure-redirect-to-basic-auth-secure-image.https-expected.txt: Added.
* http/tests/security/mixedContent/secure-redirect-to-insecure-redirect-to-basic-auth-secure-image.https.html: Added.
* http/tests/security/mixedContent/secure-redirect-to-secure-redirect-to-basic-auth-insecure-image.https-expected.txt: Added.
* http/tests/security/mixedContent/secure-redirect-to-secure-redirect-to-basic-auth-insecure-image.https.html: Added.
* http/tests/security/mixedContent/secure-redirect-to-secure-redirect-to-basic-auth-secure-image.https-expected.txt: Added.
* http/tests/security/mixedContent/secure-redirect-to-secure-redirect-to-basic-auth-secure-image.https.html: Added.
* platform/ios-wk1/http/tests/security/mixedContent/secure-redirect-to-secure-redirect-to-basic-auth-secure-image.https-expected.txt: Added.
* platform/mac-wk1/http/tests/security/mixedContent/secure-redirect-to-secure-redirect-to-basic-auth-secure-image.https-expected.txt: Added.
* platform/win/http/tests/security/mixedContent/secure-redirect-to-secure-redirect-to-basic-auth-secure-image.https-expected.txt: Added.

git-svn-id: http://svn.webkit.org/repository/webkit/trunk@224134 268f45cc-cd09-0410-ab3c-d52691b4dbfc

42 files changed:
LayoutTests/ChangeLog
LayoutTests/http/tests/security/mixedContent/insecure-download-redirects-to-basic-auth-secure-download.https-expected.txt [new file with mode: 0644]
LayoutTests/http/tests/security/mixedContent/insecure-download-redirects-to-basic-auth-secure-download.https.html [new file with mode: 0644]
LayoutTests/http/tests/security/mixedContent/insecure-image-redirects-to-basic-auth-secure-image-expected.txt [new file with mode: 0644]
LayoutTests/http/tests/security/mixedContent/insecure-image-redirects-to-basic-auth-secure-image.html [new file with mode: 0644]
LayoutTests/http/tests/security/mixedContent/insecure-script-redirects-to-basic-auth-secure-script-expected.https.txt [new file with mode: 0644]
LayoutTests/http/tests/security/mixedContent/insecure-script-redirects-to-basic-auth-secure-script-expected.txt [new file with mode: 0644]
LayoutTests/http/tests/security/mixedContent/insecure-script-redirects-to-basic-auth-secure-script.html [new file with mode: 0644]
LayoutTests/http/tests/security/mixedContent/insecure-stylesheet-redirects-to-basic-auth-secure-stylesheet-expected.txt [new file with mode: 0644]
LayoutTests/http/tests/security/mixedContent/insecure-stylesheet-redirects-to-basic-auth-secure-stylesheet.html [new file with mode: 0644]
LayoutTests/http/tests/security/mixedContent/resources/frame-with-insecure-image-redirects-to-basic-auth-secure-image.html [new file with mode: 0644]
LayoutTests/http/tests/security/mixedContent/resources/frame-with-insecure-script-redirects-to-basic-auth-secure-script.html [new file with mode: 0644]
LayoutTests/http/tests/security/mixedContent/resources/frame-with-insecure-stylesheet-redirects-to-basic-auth-secure-stylesheet.html [new file with mode: 0644]
LayoutTests/http/tests/security/mixedContent/resources/frame-with-programmatically-added-insecure-image-redirects-to-basic-auth-secure-image.html [new file with mode: 0644]
LayoutTests/http/tests/security/mixedContent/resources/subresource/protected-image.php [new file with mode: 0644]
LayoutTests/http/tests/security/mixedContent/resources/subresource/protected-pdf.php [new file with mode: 0644]
LayoutTests/http/tests/security/mixedContent/resources/subresource/protected-script.php [new file with mode: 0644]
LayoutTests/http/tests/security/mixedContent/resources/subresource/protected-stylesheet.php [new file with mode: 0644]
LayoutTests/http/tests/security/mixedContent/secure-redirect-to-insecure-redirect-to-basic-auth-secure-image.https-expected.txt [new file with mode: 0644]
LayoutTests/http/tests/security/mixedContent/secure-redirect-to-insecure-redirect-to-basic-auth-secure-image.https.html [new file with mode: 0644]
LayoutTests/http/tests/security/mixedContent/secure-redirect-to-secure-redirect-to-basic-auth-insecure-image.https-expected.txt [new file with mode: 0644]
LayoutTests/http/tests/security/mixedContent/secure-redirect-to-secure-redirect-to-basic-auth-insecure-image.https.html [new file with mode: 0644]
LayoutTests/http/tests/security/mixedContent/secure-redirect-to-secure-redirect-to-basic-auth-secure-image.https-expected.txt [new file with mode: 0644]
LayoutTests/http/tests/security/mixedContent/secure-redirect-to-secure-redirect-to-basic-auth-secure-image.https.html [new file with mode: 0644]
LayoutTests/platform/ios-wk1/http/tests/security/mixedContent/secure-redirect-to-secure-redirect-to-basic-auth-secure-image.https-expected.txt [new file with mode: 0644]
LayoutTests/platform/mac-wk1/http/tests/security/mixedContent/secure-redirect-to-secure-redirect-to-basic-auth-secure-image.https-expected.txt [new file with mode: 0644]
LayoutTests/platform/win/http/tests/security/mixedContent/secure-redirect-to-secure-redirect-to-basic-auth-secure-image.https-expected.txt [new file with mode: 0644]
Source/WebCore/ChangeLog
Source/WebCore/loader/ResourceLoader.cpp
Source/WebCore/loader/ResourceLoader.h
Source/WebKit/ChangeLog
Source/WebKit/NetworkProcess/Downloads/PendingDownload.cpp
Source/WebKit/NetworkProcess/Downloads/PendingDownload.h
Source/WebKit/NetworkProcess/NetworkLoad.cpp
Source/WebKit/NetworkProcess/NetworkLoad.h
Source/WebKit/NetworkProcess/NetworkLoadClient.h
Source/WebKit/NetworkProcess/NetworkResourceLoader.cpp
Source/WebKit/NetworkProcess/NetworkResourceLoader.h
Source/WebKit/NetworkProcess/NetworkResourceLoader.messages.in
Source/WebKit/NetworkProcess/PreconnectTask.h
Source/WebKit/NetworkProcess/cache/NetworkCacheSpeculativeLoad.h
Source/WebKit/WebProcess/Network/WebResourceLoader.cpp

index 2df4eb2..ae13b0b 100644 (file)
@@ -1,5 +1,40 @@
 2017-10-27  Daniel Bates  <dabates@apple.com>
 
+        Only allow non-mixed content protected subresources to ask for credentials
+        https://bugs.webkit.org/show_bug.cgi?id=178919
+        <rdar://problem/35015245>
+
+        Reviewed by Alex Christensen.
+
+        * http/tests/security/mixedContent/insecure-download-redirects-to-basic-auth-secure-download.https-expected.txt: Added.
+        * http/tests/security/mixedContent/insecure-download-redirects-to-basic-auth-secure-download.https.html: Added.
+        * http/tests/security/mixedContent/insecure-image-redirects-to-basic-auth-secure-image-expected.txt: Added.
+        * http/tests/security/mixedContent/insecure-image-redirects-to-basic-auth-secure-image.html: Added.
+        * http/tests/security/mixedContent/insecure-script-redirects-to-basic-auth-secure-script-expected.https.txt: Added.
+        * http/tests/security/mixedContent/insecure-script-redirects-to-basic-auth-secure-script-expected.txt: Added.
+        * http/tests/security/mixedContent/insecure-script-redirects-to-basic-auth-secure-script.html: Added.
+        * http/tests/security/mixedContent/insecure-stylesheet-redirects-to-basic-auth-secure-stylesheet-expected.txt: Added.
+        * http/tests/security/mixedContent/insecure-stylesheet-redirects-to-basic-auth-secure-stylesheet.html: Added.
+        * http/tests/security/mixedContent/resources/frame-with-insecure-image-redirects-to-basic-auth-secure-image.html: Added.
+        * http/tests/security/mixedContent/resources/frame-with-insecure-script-redirects-to-basic-auth-secure-script.html: Added.
+        * http/tests/security/mixedContent/resources/frame-with-insecure-stylesheet-redirects-to-basic-auth-secure-stylesheet.html: Added.
+        * http/tests/security/mixedContent/resources/frame-with-programmatically-added-insecure-image-redirects-to-basic-auth-secure-image.html: Added.
+        * http/tests/security/mixedContent/resources/subresource/protected-image.php: Added.
+        * http/tests/security/mixedContent/resources/subresource/protected-pdf.php: Added.
+        * http/tests/security/mixedContent/resources/subresource/protected-script.php: Added.
+        * http/tests/security/mixedContent/resources/subresource/protected-stylesheet.php: Added.
+        * http/tests/security/mixedContent/secure-redirect-to-insecure-redirect-to-basic-auth-secure-image.https-expected.txt: Added.
+        * http/tests/security/mixedContent/secure-redirect-to-insecure-redirect-to-basic-auth-secure-image.https.html: Added.
+        * http/tests/security/mixedContent/secure-redirect-to-secure-redirect-to-basic-auth-insecure-image.https-expected.txt: Added.
+        * http/tests/security/mixedContent/secure-redirect-to-secure-redirect-to-basic-auth-insecure-image.https.html: Added.
+        * http/tests/security/mixedContent/secure-redirect-to-secure-redirect-to-basic-auth-secure-image.https-expected.txt: Added.
+        * http/tests/security/mixedContent/secure-redirect-to-secure-redirect-to-basic-auth-secure-image.https.html: Added.
+        * platform/ios-wk1/http/tests/security/mixedContent/secure-redirect-to-secure-redirect-to-basic-auth-secure-image.https-expected.txt: Added.
+        * platform/mac-wk1/http/tests/security/mixedContent/secure-redirect-to-secure-redirect-to-basic-auth-secure-image.https-expected.txt: Added.
+        * platform/win/http/tests/security/mixedContent/secure-redirect-to-secure-redirect-to-basic-auth-secure-image.https-expected.txt: Added.
+
+2017-10-27  Daniel Bates  <dabates@apple.com>
+
         Add tests for automatic decompression of gzip-compressed subresources
         https://bugs.webkit.org/show_bug.cgi?id=178941
         <rdar://problem/35230090>
diff --git a/LayoutTests/http/tests/security/mixedContent/insecure-download-redirects-to-basic-auth-secure-download.https-expected.txt b/LayoutTests/http/tests/security/mixedContent/insecure-download-redirects-to-basic-auth-secure-download.https-expected.txt
new file mode 100644 (file)
index 0000000..6f08f37
--- /dev/null
@@ -0,0 +1,2 @@
+ALERT: Unauthorized
+
diff --git a/LayoutTests/http/tests/security/mixedContent/insecure-download-redirects-to-basic-auth-secure-download.https.html b/LayoutTests/http/tests/security/mixedContent/insecure-download-redirects-to-basic-auth-secure-download.https.html
new file mode 100644 (file)
index 0000000..e150be4
--- /dev/null
@@ -0,0 +1,30 @@
+<!DOCTYPE html>
+<html>
+<head>
+<script src="/js-test-resources/ui-helper.js"></script>
+<script>
+if (window.testRunner) {
+    testRunner.dumpAsText();
+    testRunner.waitUntilDone();
+    testRunner.setHandlesAuthenticationChallenges(true);
+    testRunner.setAuthenticationUsername("testUser");
+    testRunner.setAuthenticationPassword("testPassword");
+    if (testRunner.isWebKit2)
+        testRunner.setShouldLogDownloadCallbacks(true);
+}
+</script>
+</head>
+<body>
+<p>
+<p>This test loads an insecure resource that redirects to a secure PDF guarded by basic authentication. The secure PDF should not be downloaded because it requires credentials and was loaded via an insecure redirect. This test PASSED if you see a JavaScript alert with message "Unauthorized". Otherwise, it FAILED.</p>
+<a id="link" href="http://127.0.0.1:8080/resources/redirect.php?url=https://localhost:8443/security/mixedContent/resources/subresource/protected-pdf.php">the link</a>.
+<script>
+function runTest()
+{
+    var link = document.getElementById("link");
+    UIHelper.activateAt(link.offsetLeft + 5, link.offsetTop + 5);
+}
+runTest();
+</script>
+</body>
+</html>
diff --git a/LayoutTests/http/tests/security/mixedContent/insecure-image-redirects-to-basic-auth-secure-image-expected.txt b/LayoutTests/http/tests/security/mixedContent/insecure-image-redirects-to-basic-auth-secure-image-expected.txt
new file mode 100644 (file)
index 0000000..8b44376
--- /dev/null
@@ -0,0 +1,5 @@
+CONSOLE MESSAGE: line 17: The page at https://127.0.0.1:8443/security/mixedContent/resources/frame-with-insecure-image-redirects-to-basic-auth-secure-image.html was allowed to display insecure content from http://127.0.0.1:8080/resources/redirect.php?url=https://localhost:8443/security/mixedContent/resources/subresource/protected-image.php.
+
+This test opens a new window to a secure page that loads an insecure image that redirects to a secure image guarded by basic authentication. The secure image should be blocked because it requires credentials and was loaded via an insecure redirect.
+
+PASS did not load image.
diff --git a/LayoutTests/http/tests/security/mixedContent/insecure-image-redirects-to-basic-auth-secure-image.html b/LayoutTests/http/tests/security/mixedContent/insecure-image-redirects-to-basic-auth-secure-image.html
new file mode 100644 (file)
index 0000000..e69eb22
--- /dev/null
@@ -0,0 +1,29 @@
+<!DOCTYPE html>
+<html>
+<body>
+<script>
+if (window.testRunner) {
+    testRunner.dumpAsText();
+    testRunner.setCanOpenWindows();
+    testRunner.setCloseRemainingWindowsWhenComplete(true);
+    testRunner.setHandlesAuthenticationChallenges(true);
+    testRunner.setAuthenticationUsername("testUser");
+    testRunner.setAuthenticationPassword("testPassword");
+    testRunner.waitUntilDone();
+}
+
+function receiveMessage(messageEvent) {
+    document.getElementById("result").textContent = messageEvent.data;
+    if (window.testRunner)
+        testRunner.notifyDone();
+}
+
+window.addEventListener("message", receiveMessage, false);
+</script>
+<p>This test opens a new window to a secure page that loads an insecure image that redirects to a secure image guarded by basic authentication. The secure image should be blocked because it requires credentials and was loaded via an insecure redirect.</p>
+<div id="result"></div>
+<script>
+window.open("https://127.0.0.1:8443/security/mixedContent/resources/frame-with-insecure-image-redirects-to-basic-auth-secure-image.html");
+</script>
+</body>
+</html>
diff --git a/LayoutTests/http/tests/security/mixedContent/insecure-script-redirects-to-basic-auth-secure-script-expected.https.txt b/LayoutTests/http/tests/security/mixedContent/insecure-script-redirects-to-basic-auth-secure-script-expected.https.txt
new file mode 100644 (file)
index 0000000..53df79a
--- /dev/null
@@ -0,0 +1,5 @@
+CONSOLE MESSAGE: [blocked] The page at https://127.0.0.1:8443/security/mixedContent/resources/frame-with-insecure-script-redirects-to-basic-auth-secure-script.html was not allowed to run insecure content from http://127.0.0.1:8080/resources/redirect.php?url=https://localhost:8443/security/mixedContent/resources/subresource/protected-script.php.
+
+This test opens a new window to a secure page that loads an insecure script that redirects to a secure script guarded by basic authentication. The secure script should be blocked because it requires credentials and was loaded via an insecure redirect.
+
+PASS did not load script.
diff --git a/LayoutTests/http/tests/security/mixedContent/insecure-script-redirects-to-basic-auth-secure-script-expected.txt b/LayoutTests/http/tests/security/mixedContent/insecure-script-redirects-to-basic-auth-secure-script-expected.txt
new file mode 100644 (file)
index 0000000..53df79a
--- /dev/null
@@ -0,0 +1,5 @@
+CONSOLE MESSAGE: [blocked] The page at https://127.0.0.1:8443/security/mixedContent/resources/frame-with-insecure-script-redirects-to-basic-auth-secure-script.html was not allowed to run insecure content from http://127.0.0.1:8080/resources/redirect.php?url=https://localhost:8443/security/mixedContent/resources/subresource/protected-script.php.
+
+This test opens a new window to a secure page that loads an insecure script that redirects to a secure script guarded by basic authentication. The secure script should be blocked because it requires credentials and was loaded via an insecure redirect.
+
+PASS did not load script.
diff --git a/LayoutTests/http/tests/security/mixedContent/insecure-script-redirects-to-basic-auth-secure-script.html b/LayoutTests/http/tests/security/mixedContent/insecure-script-redirects-to-basic-auth-secure-script.html
new file mode 100644 (file)
index 0000000..211ba9f
--- /dev/null
@@ -0,0 +1,29 @@
+<!DOCTYPE html>
+<html>
+<body>
+<script>
+if (window.testRunner) {
+    testRunner.dumpAsText();
+    testRunner.setCanOpenWindows();
+    testRunner.setCloseRemainingWindowsWhenComplete(true);
+    testRunner.setHandlesAuthenticationChallenges(true);
+    testRunner.setAuthenticationUsername("testUser");
+    testRunner.setAuthenticationPassword("testPassword");
+    testRunner.waitUntilDone();
+}
+
+function receiveMessage(messageEvent) {
+    document.getElementById("result").textContent = messageEvent.data;
+    if (window.testRunner)
+        testRunner.notifyDone();
+}
+
+window.addEventListener("message", receiveMessage, false);
+</script>
+<p>This test opens a new window to a secure page that loads an insecure script that redirects to a secure script guarded by basic authentication. The secure script should be blocked because it requires credentials and was loaded via an insecure redirect.</p>
+<div id="result"></div>
+<script>
+window.open("https://127.0.0.1:8443/security/mixedContent/resources/frame-with-insecure-script-redirects-to-basic-auth-secure-script.html");
+</script>
+</body>
+</html>
diff --git a/LayoutTests/http/tests/security/mixedContent/insecure-stylesheet-redirects-to-basic-auth-secure-stylesheet-expected.txt b/LayoutTests/http/tests/security/mixedContent/insecure-stylesheet-redirects-to-basic-auth-secure-stylesheet-expected.txt
new file mode 100644 (file)
index 0000000..4220cc7
--- /dev/null
@@ -0,0 +1,5 @@
+CONSOLE MESSAGE: line 14: [blocked] The page at https://127.0.0.1:8443/security/mixedContent/resources/frame-with-insecure-stylesheet-redirects-to-basic-auth-secure-stylesheet.html was not allowed to run insecure content from http://127.0.0.1:8080/resources/redirect.php?url=https://localhost:8443/security/mixedContent/resources/subresource/protected-stylesheet.php.
+
+This test opens a new window to a secure page that loads an insecure stylesheet that redirects to a secure stylesheet guarded by basic authentication. The secure script should be blocked because it requires credentials and was loaded via an insecure redirect.
+
+PASS did not load stylesheet.
diff --git a/LayoutTests/http/tests/security/mixedContent/insecure-stylesheet-redirects-to-basic-auth-secure-stylesheet.html b/LayoutTests/http/tests/security/mixedContent/insecure-stylesheet-redirects-to-basic-auth-secure-stylesheet.html
new file mode 100644 (file)
index 0000000..3fa7132
--- /dev/null
@@ -0,0 +1,29 @@
+<!DOCTYPE html>
+<html>
+<body>
+<script>
+if (window.testRunner) {
+    testRunner.dumpAsText();
+    testRunner.setCanOpenWindows();
+    testRunner.setCloseRemainingWindowsWhenComplete(true);
+    testRunner.setHandlesAuthenticationChallenges(true);
+    testRunner.setAuthenticationUsername("testUser");
+    testRunner.setAuthenticationPassword("testPassword");
+    testRunner.waitUntilDone();
+}
+
+function receiveMessage(messageEvent) {
+    document.getElementById("result").textContent = messageEvent.data;
+    if (window.testRunner)
+        testRunner.notifyDone();
+}
+
+window.addEventListener("message", receiveMessage, false);
+</script>
+<p>This test opens a new window to a secure page that loads an insecure stylesheet that redirects to a secure stylesheet guarded by basic authentication. The secure script should be blocked because it requires credentials and was loaded via an insecure redirect.</p>
+<div id="result"></div>
+<script>
+window.open("https://127.0.0.1:8443/security/mixedContent/resources/frame-with-insecure-stylesheet-redirects-to-basic-auth-secure-stylesheet.html");
+</script>
+</body>
+</html>
diff --git a/LayoutTests/http/tests/security/mixedContent/resources/frame-with-insecure-image-redirects-to-basic-auth-secure-image.html b/LayoutTests/http/tests/security/mixedContent/resources/frame-with-insecure-image-redirects-to-basic-auth-secure-image.html
new file mode 100644 (file)
index 0000000..111f719
--- /dev/null
@@ -0,0 +1,19 @@
+<!DOCTYPE html>
+<html>
+<head>
+<script>
+function pass()
+{
+    window.opener.postMessage("PASS did not load image.", "*");
+}
+
+function fail()
+{
+    window.opener.postMessage("FAIL did load image.", "*");
+}
+</script>
+</head>
+<body>
+<img src="http://127.0.0.1:8080/resources/redirect.php?url=https://localhost:8443/security/mixedContent/resources/subresource/protected-image.php" onerror="pass()" onload="fail()">
+</body>
+</html>
diff --git a/LayoutTests/http/tests/security/mixedContent/resources/frame-with-insecure-script-redirects-to-basic-auth-secure-script.html b/LayoutTests/http/tests/security/mixedContent/resources/frame-with-insecure-script-redirects-to-basic-auth-secure-script.html
new file mode 100644 (file)
index 0000000..5682b4b
--- /dev/null
@@ -0,0 +1,19 @@
+<!DOCTYPE html>
+<html>
+<head>
+<script>
+function pass()
+{
+    window.opener.postMessage("PASS did not load script.", "*");
+}
+
+function fail()
+{
+    window.opener.postMessage("FAIL did load script.", "*");
+}
+</script>
+</head>
+<body>
+<script src="http://127.0.0.1:8080/resources/redirect.php?url=https://localhost:8443/security/mixedContent/resources/subresource/protected-script.php" onerror="pass()" onload="fail()"></script>
+</body>
+</html>
diff --git a/LayoutTests/http/tests/security/mixedContent/resources/frame-with-insecure-stylesheet-redirects-to-basic-auth-secure-stylesheet.html b/LayoutTests/http/tests/security/mixedContent/resources/frame-with-insecure-stylesheet-redirects-to-basic-auth-secure-stylesheet.html
new file mode 100644 (file)
index 0000000..df62bcd
--- /dev/null
@@ -0,0 +1,18 @@
+<!DOCTYPE html>
+<html>
+<head>
+<script>
+function checkDidLoadStylesheet()
+{
+    if (document.styleSheets.length)
+        window.opener.postMessage("FAIL did load stylesheet.", "*");
+    else
+        window.opener.postMessage("PASS did not load stylesheet.", "*");
+}
+</script>
+<!-- For some reason, a blocked stylesheet is not treated as a network error. -->
+<link rel="stylesheet" href="http://127.0.0.1:8080/resources/redirect.php?url=https://localhost:8443/security/mixedContent/resources/subresource/protected-stylesheet.php" onload="checkDidLoadStylesheet()">
+</head>
+<body>
+</body>
+</html>
diff --git a/LayoutTests/http/tests/security/mixedContent/resources/frame-with-programmatically-added-insecure-image-redirects-to-basic-auth-secure-image.html b/LayoutTests/http/tests/security/mixedContent/resources/frame-with-programmatically-added-insecure-image-redirects-to-basic-auth-secure-image.html
new file mode 100644 (file)
index 0000000..31fe947
--- /dev/null
@@ -0,0 +1,27 @@
+<!DOCTYPE html>
+<html>
+<head>
+<script>
+function pass()
+{
+    window.opener.postMessage("PASS did not load image.", "*");
+}
+
+function fail()
+{
+    window.opener.postMessage("FAIL did load image.", "*");
+}
+
+window.onload = function ()
+{
+    var image = new Image;
+    image.onerror = pass;
+    image.onload = fail;
+    image.src = "http://127.0.0.1:8080/resources/redirect.php?url=https://localhost:8443/security/mixedContent/resources/subresource/protected-image.php";
+    document.body.appendChild(image);
+}
+</script>
+</head>
+<body>
+</body>
+</html>
diff --git a/LayoutTests/http/tests/security/mixedContent/resources/subresource/protected-image.php b/LayoutTests/http/tests/security/mixedContent/resources/subresource/protected-image.php
new file mode 100644 (file)
index 0000000..39b0271
--- /dev/null
@@ -0,0 +1,12 @@
+<?php
+header("Cache-Control: no-store");
+header("Connection: close");
+if (!isset($_SERVER["PHP_AUTH_USER"])) {
+    header("WWW-authenticate: Basic realm=\"" . $_SERVER["REQUEST_URI"] . "\"");
+    header("HTTP/1.0 401 Unauthorized");
+    exit;
+}
+// Authenticated
+header("Content-Type: image/png");
+echo file_get_contents("../../../contentSecurityPolicy/block-all-mixed-content/resources/red-square.png");
+?>
diff --git a/LayoutTests/http/tests/security/mixedContent/resources/subresource/protected-pdf.php b/LayoutTests/http/tests/security/mixedContent/resources/subresource/protected-pdf.php
new file mode 100644 (file)
index 0000000..f801ca6
--- /dev/null
@@ -0,0 +1,14 @@
+<?php
+header("Cache-Control: no-store");
+header("Connection: close");
+if (!isset($_SERVER["PHP_AUTH_USER"])) {
+    header("WWW-authenticate: Basic realm=\"" . $_SERVER["REQUEST_URI"] . "\"");
+    header("HTTP/1.0 401 Unauthorized");
+    echo "<script>alert('Unauthorized'); window.testRunner && window.testRunner.notifyDone()</script>";
+    exit;
+}
+// Authenticated
+header("Content-Type: application/pdf");
+header("Content-Disposition: attachment; filename=test.pdf");
+echo file_get_contents("../../../../media/resources/test.pdf");
+?>
diff --git a/LayoutTests/http/tests/security/mixedContent/resources/subresource/protected-script.php b/LayoutTests/http/tests/security/mixedContent/resources/subresource/protected-script.php
new file mode 100644 (file)
index 0000000..77bc277
--- /dev/null
@@ -0,0 +1,12 @@
+<?php
+header("Cache-Control: no-store");
+header("Connection: close");
+if (!isset($_SERVER["PHP_AUTH_USER"])) {
+    header("WWW-authenticate: Basic realm=\"" . $_SERVER["REQUEST_URI"] . "\"");
+    header("HTTP/1.0 401 Unauthorized");
+    exit;
+}
+// Authenticated
+header("Content-Type: text/javascript");
+echo file_get_contents("../../../contentSecurityPolicy/resources/alert-fail.js");
+?>
diff --git a/LayoutTests/http/tests/security/mixedContent/resources/subresource/protected-stylesheet.php b/LayoutTests/http/tests/security/mixedContent/resources/subresource/protected-stylesheet.php
new file mode 100644 (file)
index 0000000..91a8623
--- /dev/null
@@ -0,0 +1,12 @@
+<?php
+header("Cache-Control: no-store");
+header("Connection: close");
+if (!isset($_SERVER["PHP_AUTH_USER"])) {
+    header("WWW-authenticate: Basic realm=\"" . $_SERVER["REQUEST_URI"] . "\"");
+    header("HTTP/1.0 401 Unauthorized");
+    exit;
+}
+// Authenticated
+header("Content-Type: text/css");
+echo file_get_contents("../../../contentSecurityPolicy/resources/style-set-red.css");
+?>
diff --git a/LayoutTests/http/tests/security/mixedContent/secure-redirect-to-insecure-redirect-to-basic-auth-secure-image.https-expected.txt b/LayoutTests/http/tests/security/mixedContent/secure-redirect-to-insecure-redirect-to-basic-auth-secure-image.https-expected.txt
new file mode 100644 (file)
index 0000000..f155229
--- /dev/null
@@ -0,0 +1,12 @@
+CONSOLE MESSAGE: The page at https://127.0.0.1:8443/security/mixedContent/secure-redirect-to-insecure-redirect-to-basic-auth-secure-image.https.html was allowed to display insecure content from http://127.0.0.1:8080/resources/redirect.php?url=https://localhost:8443/security/mixedContent/resources/subresource/protected-image.php.
+
+This test loads a secure image that redirects to an insecure image that redirects to a secure image guarded by basic authentication. The secure image should be blocked because it requires credentials and was loaded via an insecure redirect.
+
+On success, you will see a series of "PASS" messages, followed by "TEST COMPLETE".
+
+
+PASS did not load image.
+PASS successfullyParsed is true
+
+TEST COMPLETE
+
diff --git a/LayoutTests/http/tests/security/mixedContent/secure-redirect-to-insecure-redirect-to-basic-auth-secure-image.https.html b/LayoutTests/http/tests/security/mixedContent/secure-redirect-to-insecure-redirect-to-basic-auth-secure-image.https.html
new file mode 100644 (file)
index 0000000..95f9c5e
--- /dev/null
@@ -0,0 +1,31 @@
+<!DOCTYPE html>
+<html>
+<body>
+<script src="/js-test-resources/js-test.js"></script>
+<script>
+if (window.testRunner) {
+    testRunner.setHandlesAuthenticationChallenges(true);
+    testRunner.setAuthenticationUsername("testUser");
+    testRunner.setAuthenticationPassword("testPassword");
+}
+
+window.jsTestIsAsync = true;
+
+function pass()
+{
+    testPassed("did not load image.");
+    finishJSTest();
+}
+
+function fail()
+{
+    testFailed("did load image.");
+    finishJSTest();
+}
+</script>
+<script>
+description("This test loads a secure image that redirects to an insecure image that redirects to a secure image guarded by basic authentication. The secure image should be blocked because it requires credentials and was loaded via an insecure redirect.");
+</script>
+<img src="https://127.0.0.1:8443/resources/redirect.php?url=http%3A//127.0.0.1%3A8080/resources/redirect.php%3Furl%3Dhttps%3A//localhost%3A8443/security/mixedContent/resources/subresource/protected-image.php" onerror="pass()" onload="fail()">
+</body>
+</html>
diff --git a/LayoutTests/http/tests/security/mixedContent/secure-redirect-to-secure-redirect-to-basic-auth-insecure-image.https-expected.txt b/LayoutTests/http/tests/security/mixedContent/secure-redirect-to-secure-redirect-to-basic-auth-insecure-image.https-expected.txt
new file mode 100644 (file)
index 0000000..7f99797
--- /dev/null
@@ -0,0 +1,12 @@
+CONSOLE MESSAGE: The page at https://127.0.0.1:8443/security/mixedContent/secure-redirect-to-secure-redirect-to-basic-auth-insecure-image.https.html was allowed to display insecure content from http://127.0.0.1:8443/resources/redirect.php?url=http://localhost:8080/security/mixedContent/resources/subresource/protected-image.php.
+
+This test loads a secure image that redirects to an secure image that redirects to an insecure image guarded by basic authentication. The insecure image should be blocked because it requires credentials.
+
+On success, you will see a series of "PASS" messages, followed by "TEST COMPLETE".
+
+
+PASS did not load image.
+PASS successfullyParsed is true
+
+TEST COMPLETE
+
diff --git a/LayoutTests/http/tests/security/mixedContent/secure-redirect-to-secure-redirect-to-basic-auth-insecure-image.https.html b/LayoutTests/http/tests/security/mixedContent/secure-redirect-to-secure-redirect-to-basic-auth-insecure-image.https.html
new file mode 100644 (file)
index 0000000..aa02137
--- /dev/null
@@ -0,0 +1,31 @@
+<!DOCTYPE html>
+<html>
+<body>
+<script src="/js-test-resources/js-test.js"></script>
+<script>
+if (window.testRunner) {
+    testRunner.setHandlesAuthenticationChallenges(true);
+    testRunner.setAuthenticationUsername("testUser");
+    testRunner.setAuthenticationPassword("testPassword");
+}
+
+window.jsTestIsAsync = true;
+
+function pass()
+{
+    testPassed("did not load image.");
+    finishJSTest();
+}
+
+function fail()
+{
+    testFailed("did load image.");
+    finishJSTest();
+}
+</script>
+<script>
+description("This test loads a secure image that redirects to an secure image that redirects to an insecure image guarded by basic authentication. The insecure image should be blocked because it requires credentials.");
+</script>
+<img src="https://127.0.0.1:8443/resources/redirect.php?url=http%3A//127.0.0.1%3A8443/resources/redirect.php%3Furl%3Dhttp%3A//localhost%3A8080/security/mixedContent/resources/subresource/protected-image.php" onerror="pass()" onload="fail()">
+</body>
+</html>
diff --git a/LayoutTests/http/tests/security/mixedContent/secure-redirect-to-secure-redirect-to-basic-auth-secure-image.https-expected.txt b/LayoutTests/http/tests/security/mixedContent/secure-redirect-to-secure-redirect-to-basic-auth-secure-image.https-expected.txt
new file mode 100644 (file)
index 0000000..3f96a8a
--- /dev/null
@@ -0,0 +1,11 @@
+localhost:8443 - didReceiveAuthenticationChallenge - Responding with testUser:testPassword
+This test loads a secure image that redirects to a secure image that redirects to a secure image guarded by basic authentication. The secure image should load.
+
+On success, you will see a series of "PASS" messages, followed by "TEST COMPLETE".
+
+
+PASS did load image.
+PASS successfullyParsed is true
+
+TEST COMPLETE
+
diff --git a/LayoutTests/http/tests/security/mixedContent/secure-redirect-to-secure-redirect-to-basic-auth-secure-image.https.html b/LayoutTests/http/tests/security/mixedContent/secure-redirect-to-secure-redirect-to-basic-auth-secure-image.https.html
new file mode 100644 (file)
index 0000000..9dd075f
--- /dev/null
@@ -0,0 +1,31 @@
+<!DOCTYPE html>
+<html>
+<body>
+<script src="/js-test-resources/js-test.js"></script>
+<script>
+if (window.testRunner) {
+    testRunner.setHandlesAuthenticationChallenges(true);
+    testRunner.setAuthenticationUsername("testUser");
+    testRunner.setAuthenticationPassword("testPassword");
+}
+
+window.jsTestIsAsync = true;
+
+function pass()
+{
+    testPassed("did load image.");
+    finishJSTest();
+}
+
+function fail()
+{
+    testFailed("did not load image.");
+    finishJSTest();
+}
+</script>
+<script>
+description("This test loads a secure image that redirects to a secure image that redirects to a secure image guarded by basic authentication. The secure image should load.");
+</script>
+<img src="https://127.0.0.1:8443/resources/redirect.php?url=https%3A//127.0.0.1%3A8443/resources/redirect.php%3Furl%3Dhttps%3A//localhost%3A8443/security/mixedContent/resources/subresource/protected-image.php" onerror="fail()" onload="pass()">
+</body>
+</html>
diff --git a/LayoutTests/platform/ios-wk1/http/tests/security/mixedContent/secure-redirect-to-secure-redirect-to-basic-auth-secure-image.https-expected.txt b/LayoutTests/platform/ios-wk1/http/tests/security/mixedContent/secure-redirect-to-secure-redirect-to-basic-auth-secure-image.https-expected.txt
new file mode 100644 (file)
index 0000000..41f5e42
--- /dev/null
@@ -0,0 +1,11 @@
+https://127.0.0.1:8443/resources/redirect.php?url=https%3A//127.0.0.1%3A8443/resources/redirect.php%3Furl%3Dhttps%3A//localhost%3A8443/security/mixedContent/resources/subresource/protected-image.php - didReceiveAuthenticationChallenge - Responding with testUser:testPassword
+This test loads a secure image that redirects to a secure image that redirects to a secure image guarded by basic authentication. The secure image should load.
+
+On success, you will see a series of "PASS" messages, followed by "TEST COMPLETE".
+
+
+PASS did load image.
+PASS successfullyParsed is true
+
+TEST COMPLETE
+
diff --git a/LayoutTests/platform/mac-wk1/http/tests/security/mixedContent/secure-redirect-to-secure-redirect-to-basic-auth-secure-image.https-expected.txt b/LayoutTests/platform/mac-wk1/http/tests/security/mixedContent/secure-redirect-to-secure-redirect-to-basic-auth-secure-image.https-expected.txt
new file mode 100644 (file)
index 0000000..41f5e42
--- /dev/null
@@ -0,0 +1,11 @@
+https://127.0.0.1:8443/resources/redirect.php?url=https%3A//127.0.0.1%3A8443/resources/redirect.php%3Furl%3Dhttps%3A//localhost%3A8443/security/mixedContent/resources/subresource/protected-image.php - didReceiveAuthenticationChallenge - Responding with testUser:testPassword
+This test loads a secure image that redirects to a secure image that redirects to a secure image guarded by basic authentication. The secure image should load.
+
+On success, you will see a series of "PASS" messages, followed by "TEST COMPLETE".
+
+
+PASS did load image.
+PASS successfullyParsed is true
+
+TEST COMPLETE
+
diff --git a/LayoutTests/platform/win/http/tests/security/mixedContent/secure-redirect-to-secure-redirect-to-basic-auth-secure-image.https-expected.txt b/LayoutTests/platform/win/http/tests/security/mixedContent/secure-redirect-to-secure-redirect-to-basic-auth-secure-image.https-expected.txt
new file mode 100644 (file)
index 0000000..41f5e42
--- /dev/null
@@ -0,0 +1,11 @@
+https://127.0.0.1:8443/resources/redirect.php?url=https%3A//127.0.0.1%3A8443/resources/redirect.php%3Furl%3Dhttps%3A//localhost%3A8443/security/mixedContent/resources/subresource/protected-image.php - didReceiveAuthenticationChallenge - Responding with testUser:testPassword
+This test loads a secure image that redirects to a secure image that redirects to a secure image guarded by basic authentication. The secure image should load.
+
+On success, you will see a series of "PASS" messages, followed by "TEST COMPLETE".
+
+
+PASS did load image.
+PASS successfullyParsed is true
+
+TEST COMPLETE
+
index b016799..700ccfb 100644 (file)
@@ -1,3 +1,34 @@
+2017-10-27  Daniel Bates  <dabates@apple.com>
+
+        Only allow non-mixed content protected subresources to ask for credentials
+        https://bugs.webkit.org/show_bug.cgi?id=178919
+        <rdar://problem/35015245>
+
+        Reviewed by Alex Christensen.
+
+        Only allow non-mixed content protected subresources to ask for credentials. It is not meaningful
+        to allow protected mixed-content subresources to ask for credentials.
+
+        Tests: http/tests/security/mixedContent/insecure-image-redirects-to-basic-auth-secure-image.html
+               http/tests/security/mixedContent/insecure-script-redirects-to-basic-auth-secure-script.html
+               http/tests/security/mixedContent/insecure-stylesheet-redirects-to-basic-auth-secure-stylesheet.html
+               http/tests/security/mixedContent/secure-redirect-to-insecure-redirect-to-basic-auth-secure-image.https.html
+               http/tests/security/mixedContent/secure-redirect-to-secure-redirect-to-basic-auth-insecure-image.https.html
+               http/tests/security/mixedContent/secure-redirect-to-secure-redirect-to-basic-auth-secure-image.https.html
+
+        * loader/ResourceLoader.cpp:
+        (WebCore::ResourceLoader::ResourceLoader): Initialize m_canAskClientForCredentials based on the
+        specified resource loader options.
+        (WebCore::ResourceLoader::init): Update m_canAskClientForCredentials based on the URL of the initial
+        request.
+        (WebCore::ResourceLoader::isMixedContent const): Helper function to check if the specified URL
+        represents a mixed content resource.
+        (WebCore::ResourceLoader::willSendRequestInternal): If the original request or the redirect request
+        is mixed content then update state such that we will disallow asking for credentials.
+        (WebCore::ResourceLoader::isAllowedToAskUserForCredentials const): Modified to use m_canAskClientForCredentials
+        when determining whether the request is allowed to ask for credentials.
+        * loader/ResourceLoader.h:
+
 2017-10-27  Chris Dumez  <cdumez@apple.com>
 
         Unskip more Service Workers tests
index 2d1bc89..e921427 100644 (file)
@@ -42,6 +42,7 @@
 #include "InspectorInstrumentation.h"
 #include "LoaderStrategy.h"
 #include "MainFrame.h"
+#include "MixedContentChecker.h"
 #include "Page.h"
 #include "PlatformStrategies.h"
 #include "ProgressTracker.h"
 namespace WebCore {
 
 ResourceLoader::ResourceLoader(Frame& frame, ResourceLoaderOptions options)
-    : m_frame(&frame)
-    , m_documentLoader(frame.loader().activeDocumentLoader())
-    , m_defersLoading(options.defersLoadingPolicy == DefersLoadingPolicy::AllowDefersLoading && frame.page()->defersLoading())
-    , m_options(options)
+    : m_frame { &frame }
+    , m_documentLoader { frame.loader().activeDocumentLoader() }
+    , m_defersLoading { options.defersLoadingPolicy == DefersLoadingPolicy::AllowDefersLoading && frame.page()->defersLoading() }
+    , m_canAskClientForCredentials { options.clientCredentialPolicy == ClientCredentialPolicy::MayAskClientForCredentials }
+    , m_options { options }
 {
 }
 
@@ -132,6 +134,7 @@ bool ResourceLoader::init(const ResourceRequest& r)
 #endif
     
     m_defersLoading = m_options.defersLoadingPolicy == DefersLoadingPolicy::AllowDefersLoading && m_frame->page()->defersLoading();
+    m_canAskClientForCredentials = m_options.clientCredentialPolicy == ClientCredentialPolicy::MayAskClientForCredentials && !isMixedContent(r.url());
 
     if (m_options.securityCheck == DoSecurityCheck && !m_frame->document()->securityOrigin().canDisplay(clientRequest.url())) {
         FrameLoader::reportLocalLoadFailed(m_frame.get(), clientRequest.url().string());
@@ -326,6 +329,16 @@ bool ResourceLoader::isSubresourceLoader()
     return false;
 }
 
+bool ResourceLoader::isMixedContent(const URL& url) const
+{
+    if (MixedContentChecker::isMixedContent(m_frame->document()->securityOrigin(), url))
+        return true;
+    Frame& topFrame = m_frame->tree().top();
+    if (&topFrame != m_frame && MixedContentChecker::isMixedContent(topFrame.document()->securityOrigin(), url))
+        return true;
+    return false;
+}
+
 void ResourceLoader::willSendRequestInternal(ResourceRequest& request, const ResourceResponse& redirectResponse)
 {
     // Protect this in this delegate method since the additional processing can do
@@ -385,6 +398,10 @@ void ResourceLoader::willSendRequestInternal(ResourceRequest& request, const Res
 #endif
 
     bool isRedirect = !redirectResponse.isNull();
+
+    if (isMixedContent(m_request.url()) || (isRedirect && isMixedContent(request.url())))
+        m_canAskClientForCredentials = false;
+
     if (isRedirect)
         platformStrategies()->loaderStrategy()->crossOriginRedirectReceived(this, request.url());
 
@@ -685,7 +702,7 @@ bool ResourceLoader::shouldUseCredentialStorage()
 
 bool ResourceLoader::isAllowedToAskUserForCredentials() const
 {
-    if (m_options.clientCredentialPolicy == ClientCredentialPolicy::CannotAskClientForCredentials)
+    if (!m_canAskClientForCredentials)
         return false;
     return m_options.credentials == FetchOptions::Credentials::Include || (m_options.credentials == FetchOptions::Credentials::SameOrigin && m_frame->document()->securityOrigin().canRequest(originalRequest().url()));
 }
index 5cd5069..f4c9a45 100644 (file)
@@ -207,6 +207,8 @@ private:
     bool shouldCacheResponse(ResourceHandle*, CFCachedURLResponseRef) override;
 #endif
 
+    bool isMixedContent(const URL&) const;
+
     ResourceRequest m_request;
     ResourceRequest m_originalRequest; // Before redirects.
     RefPtr<SharedBuffer> m_resourceData;
@@ -225,6 +227,7 @@ private:
     CancellationStatus m_cancellationStatus { NotCancelled };
 
     bool m_defersLoading;
+    bool m_canAskClientForCredentials;
     ResourceRequest m_deferredRequest;
     ResourceLoaderOptions m_options;
 
index 6fb189b..81568f7 100644 (file)
@@ -1,3 +1,42 @@
+2017-10-27  Daniel Bates  <dabates@apple.com>
+
+        Only allow non-mixed content protected subresources to ask for credentials
+        https://bugs.webkit.org/show_bug.cgi?id=178919
+        <rdar://problem/35015245>
+
+        Reviewed by Alex Christensen.
+
+        Only allow non-mixed content protected subresources to ask for credentials. It is not meaningful
+        to allow protected mixed-content subresources to ask for credentials.
+
+        * NetworkProcess/Downloads/PendingDownload.cpp:
+        (WebKit::PendingDownload::PendingDownload): Initialize m_isAllowedToAskUserForCredentials based on
+        the specified resource load parameters or NetworkLoad object.
+        * NetworkProcess/Downloads/PendingDownload.h: Add override for NetworkLoadClient::isAllowedToAskUserForCredentials().
+        * NetworkProcess/NetworkLoad.cpp:
+        (WebKit::NetworkLoad::isAllowedToAskUserForCredentials const): Added.
+        (WebKit::NetworkLoad::completeAuthenticationChallenge): Ask NetworkLoadClient whether the load is
+        allowed to prompt for credentials.
+        (WebKit::NetworkLoad::didReceiveAuthenticationChallenge): Ditto.
+        * NetworkProcess/NetworkLoad.h:
+        * NetworkProcess/NetworkLoadClient.h:
+        * NetworkProcess/NetworkResourceLoader.cpp:
+        (WebKit::NetworkResourceLoader::NetworkResourceLoader): Initialize m_isAllowedToAskUserForCredentials
+        based on the specified resource load parameters.
+        (WebKit::NetworkResourceLoader::willSendRedirectedRequest): We do not support prompting for credentials
+        for synchronous loads.
+        (WebKit::NetworkResourceLoader::continueWillSendRequest): Modified to take an argument as to whether the
+        load is allowed to ask the user for credentials and updates state.
+        * NetworkProcess/NetworkResourceLoader.h:
+        * NetworkProcess/NetworkResourceLoader.messages.in: Modified message ContinueWillSendRequest to take a
+        boolean as to whether the load is allowed to ask the user for credentials.
+        * NetworkProcess/PreconnectTask.h: Override NetworkLoadClient::isAllowedToAskUserForCredentials()
+        such that we never ask for credentials. This matches our current behavior.
+        * NetworkProcess/cache/NetworkCacheSpeculativeLoad.h: Ditto.
+        * WebProcess/Network/WebResourceLoader.cpp:
+        (WebKit::WebResourceLoader::willSendRequest): Query ResourceLoader as to whether the load is allowed to
+        ask the user for credentials and pass this state to NetworkResourceLoader.
+
 2017-10-27  Adrian Perez de Castro  <aperez@igalia.com>
 
         [GTK][CMake] Incorrect conditional check when adding build dir to GIR runtime library path
index 78f9d9b..0892e0b 100644 (file)
@@ -41,6 +41,8 @@ namespace WebKit {
 PendingDownload::PendingDownload(NetworkLoadParameters&& parameters, DownloadID downloadID, NetworkSession& networkSession, const String& suggestedName)
     : m_networkLoad(std::make_unique<NetworkLoad>(*this, WTFMove(parameters), networkSession))
 {
+    m_isAllowedToAskUserForCredentials = parameters.clientCredentialPolicy == ClientCredentialPolicy::MayAskClientForCredentials;
+
     m_networkLoad->setPendingDownloadID(downloadID);
     m_networkLoad->setPendingDownload(*this);
     m_networkLoad->setSuggestedFilename(suggestedName);
@@ -51,6 +53,8 @@ PendingDownload::PendingDownload(NetworkLoadParameters&& parameters, DownloadID
 PendingDownload::PendingDownload(std::unique_ptr<NetworkLoad>&& networkLoad, DownloadID downloadID, const ResourceRequest& request, const ResourceResponse& response)
     : m_networkLoad(WTFMove(networkLoad))
 {
+    m_isAllowedToAskUserForCredentials = m_networkLoad->isAllowedToAskUserForCredentials();
+
     m_networkLoad->setPendingDownloadID(downloadID);
     send(Messages::DownloadProxy::DidStart(request, String()));
 
index a0e2c99..7462a58 100644 (file)
@@ -58,6 +58,7 @@ private:
     void canAuthenticateAgainstProtectionSpaceAsync(const WebCore::ProtectionSpace&) override;
 #endif
     bool isSynchronous() const override { return false; }
+    bool isAllowedToAskUserForCredentials() const final { return m_isAllowedToAskUserForCredentials; }
     void willSendRedirectedRequest(WebCore::ResourceRequest&&, WebCore::ResourceRequest&& redirectRequest, WebCore::ResourceResponse&& redirectResponse) override;
     ShouldContinueDidReceiveResponse didReceiveResponse(WebCore::ResourceResponse&&) override { return ShouldContinueDidReceiveResponse::No; };
     void didReceiveBuffer(Ref<WebCore::SharedBuffer>&&, int reportedEncodedDataLength) override { };
@@ -70,6 +71,7 @@ private:
 
 private:
     std::unique_ptr<NetworkLoad> m_networkLoad;
+    bool m_isAllowedToAskUserForCredentials;
 };
 
 }
index de9eb5d..a3c95dd 100644 (file)
@@ -326,10 +326,15 @@ void NetworkLoad::didReceiveChallenge(const AuthenticationChallenge& challenge,
 #endif
 }
 
+bool NetworkLoad::isAllowedToAskUserForCredentials() const
+{
+    return m_client.get().isAllowedToAskUserForCredentials();
+}
+
 void NetworkLoad::completeAuthenticationChallenge(ChallengeCompletionHandler&& completionHandler)
 {
     bool isServerTrustEvaluation = m_challenge->protectionSpace().authenticationScheme() == ProtectionSpaceAuthenticationSchemeServerTrustEvaluationRequested;
-    if (m_parameters.clientCredentialPolicy == ClientCredentialPolicy::CannotAskClientForCredentials && !isServerTrustEvaluation) {
+    if (!isAllowedToAskUserForCredentials() && !isServerTrustEvaluation) {
         completionHandler(AuthenticationChallengeDisposition::UseCredential, { });
         return;
     }
@@ -553,7 +558,7 @@ void NetworkLoad::didReceiveAuthenticationChallenge(ResourceHandle* handle, cons
 {
     ASSERT_UNUSED(handle, handle == m_handle);
 
-    if (m_parameters.clientCredentialPolicy == ClientCredentialPolicy::CannotAskClientForCredentials) {
+    if (!isAllowedToAskUserForCredentials()) {
         challenge.authenticationClient()->receivedRequestToContinueWithoutCredential(challenge);
         return;
     }
index d697298..36ae929 100644 (file)
@@ -64,6 +64,8 @@ public:
     void setDefersLoading(bool);
     void cancel();
 
+    bool isAllowedToAskUserForCredentials() const;
+
     const WebCore::ResourceRequest& currentRequest() const { return m_currentRequest; }
     void clearCurrentRequest() { m_currentRequest = WebCore::ResourceRequest(); }
 
index 2871d32..6438427 100644 (file)
@@ -48,6 +48,8 @@ public:
 
     virtual bool isSynchronous() const = 0;
 
+    virtual bool isAllowedToAskUserForCredentials() const = 0;
+
     virtual void didSendData(unsigned long long bytesSent, unsigned long long totalBytesToBeSent) = 0;
 #if USE(PROTECTION_SPACE_AUTH_CALLBACK)
     virtual void canAuthenticateAgainstProtectionSpaceAsync(const WebCore::ProtectionSpace&) = 0;
index 1d08759..48c5497 100644 (file)
@@ -82,11 +82,12 @@ static void sendReplyToSynchronousRequest(NetworkResourceLoader::SynchronousLoad
 }
 
 NetworkResourceLoader::NetworkResourceLoader(const NetworkResourceLoadParameters& parameters, NetworkConnectionToWebProcess& connection, RefPtr<Messages::NetworkConnectionToWebProcess::PerformSynchronousLoad::DelayedReply>&& synchronousReply)
-    : m_parameters(parameters)
-    , m_connection(connection)
-    , m_defersLoading(parameters.defersLoading)
-    , m_bufferingTimer(*this, &NetworkResourceLoader::bufferingTimerFired)
-    , m_cache(sessionID().isEphemeral() ? nullptr : NetworkProcess::singleton().cache())
+    : m_parameters { parameters }
+    , m_connection { connection }
+    , m_defersLoading { parameters.defersLoading }
+    , m_isAllowedToAskUserForCredentials { parameters.clientCredentialPolicy == ClientCredentialPolicy::MayAskClientForCredentials }
+    , m_bufferingTimer { *this, &NetworkResourceLoader::bufferingTimerFired }
+    , m_cache { sessionID().isEphemeral() ? nullptr : NetworkProcess::singleton().cache() }
 {
     ASSERT(RunLoop::isMain());
     // FIXME: This is necessary because of the existence of EmptyFrameLoaderClient in WebCore.
@@ -440,7 +441,9 @@ void NetworkResourceLoader::willSendRedirectedRequest(ResourceRequest&& request,
             m_networkLoad->clearCurrentRequest();
             overridenRequest = ResourceRequest();
         }
-        continueWillSendRequest(WTFMove(overridenRequest));
+        // We do not support prompting for credentials for synchronous loads. If we ever change this policy then
+        // we need to take care to prompt if and only if request and redirectRequest are not mixed content.
+        continueWillSendRequest(WTFMove(overridenRequest), false);
         return;
     }
     send(Messages::WebResourceLoader::WillSendRequest(redirectRequest, redirectResponse));
@@ -449,10 +452,12 @@ void NetworkResourceLoader::willSendRedirectedRequest(ResourceRequest&& request,
         m_cache->storeRedirect(request, redirectResponse, redirectRequest);
 }
 
-void NetworkResourceLoader::continueWillSendRequest(ResourceRequest&& newRequest)
+void NetworkResourceLoader::continueWillSendRequest(ResourceRequest&& newRequest, bool isAllowedToAskUserForCredentials)
 {
     RELEASE_LOG_IF_ALLOWED("continueWillSendRequest: (pageID = %" PRIu64 ", frameID = %" PRIu64 ", resourceID = %" PRIu64 ")", m_parameters.webPageID, m_parameters.webFrameID, m_parameters.identifier);
 
+    m_isAllowedToAskUserForCredentials = isAllowedToAskUserForCredentials;
+
     // If there is a match in the network cache, we need to reuse the original cache policy and partition.
     newRequest.setCachePolicy(originalRequest().cachePolicy());
     newRequest.setCachePartition(originalRequest().cachePartition());
index 1963a2a..8f37242 100644 (file)
@@ -72,7 +72,7 @@ public:
 #if USE(PROTECTION_SPACE_AUTH_CALLBACK)
     void continueCanAuthenticateAgainstProtectionSpace(bool);
 #endif
-    void continueWillSendRequest(WebCore::ResourceRequest&& newRequest);
+    void continueWillSendRequest(WebCore::ResourceRequest&& newRequest, bool isAllowedToAskUserForCredentials);
 
     const WebCore::ResourceResponse& response() const { return m_response; }
 
@@ -90,6 +90,7 @@ public:
     void canAuthenticateAgainstProtectionSpaceAsync(const WebCore::ProtectionSpace&) override;
 #endif
     bool isSynchronous() const override;
+    bool isAllowedToAskUserForCredentials() const override { return m_isAllowedToAskUserForCredentials; }
     void willSendRedirectedRequest(WebCore::ResourceRequest&&, WebCore::ResourceRequest&& redirectRequest, WebCore::ResourceResponse&&) override;
     ShouldContinueDidReceiveResponse didReceiveResponse(WebCore::ResourceResponse&&) override;
     void didReceiveBuffer(Ref<WebCore::SharedBuffer>&&, int reportedEncodedDataLength) override;
@@ -152,6 +153,7 @@ private:
     bool m_wasStarted { false };
     bool m_didConsumeSandboxExtensions { false };
     bool m_defersLoading { false };
+    bool m_isAllowedToAskUserForCredentials { false };
     size_t m_numBytesReceived { 0 };
 
     unsigned m_retrievedDerivedDataCount { 0 };
index 2cb76e4..618ea79 100644 (file)
@@ -22,6 +22,6 @@
 
 messages -> NetworkResourceLoader LegacyReceiver {
 
-    ContinueWillSendRequest(WebCore::ResourceRequest request)
+    ContinueWillSendRequest(WebCore::ResourceRequest request, bool isAllowedToAskUserForCredentials)
     ContinueDidReceiveResponse()
 }
index 89eabab..7af0188 100644 (file)
@@ -52,6 +52,7 @@ public:
 private:
     // NetworkLoadClient.
     bool isSynchronous() const final { return false; }
+    bool isAllowedToAskUserForCredentials() const final { return false; }
     void didSendData(unsigned long long bytesSent, unsigned long long totalBytesToBeSent) final;
     void canAuthenticateAgainstProtectionSpaceAsync(const WebCore::ProtectionSpace&) final;
     void willSendRedirectedRequest(WebCore::ResourceRequest&&, WebCore::ResourceRequest&& redirectRequest, WebCore::ResourceResponse&& redirectResponse) final;
index c16bc02..fc25d3d 100644 (file)
@@ -57,6 +57,7 @@ private:
     void canAuthenticateAgainstProtectionSpaceAsync(const WebCore::ProtectionSpace&) override;
 #endif
     bool isSynchronous() const override { return false; }
+    bool isAllowedToAskUserForCredentials() const final { return false; }
     void willSendRedirectedRequest(WebCore::ResourceRequest&&, WebCore::ResourceRequest&& redirectRequest, WebCore::ResourceResponse&& redirectResponse) override;
     ShouldContinueDidReceiveResponse didReceiveResponse(WebCore::ResourceResponse&&) override;
     void didReceiveBuffer(Ref<WebCore::SharedBuffer>&&, int reportedEncodedDataLength) override;
index a3b9cac..6c2596b 100644 (file)
@@ -94,7 +94,7 @@ void WebResourceLoader::willSendRequest(ResourceRequest&& proposedRequest, Resou
         if (!protectedThis->m_coreLoader)
             return;
 
-        protectedThis->send(Messages::NetworkResourceLoader::ContinueWillSendRequest(request));
+        protectedThis->send(Messages::NetworkResourceLoader::ContinueWillSendRequest(request, protectedThis->m_coreLoader->isAllowedToAskUserForCredentials()));
     });
 }