WebCore: https://bugs.webkit.org/show_bug.cgi?id=24853: Provide a way for WebKit...
authorlevin@chromium.org <levin@chromium.org@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Thu, 20 Aug 2009 06:28:48 +0000 (06:28 +0000)
committerlevin@chromium.org <levin@chromium.org@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Thu, 20 Aug 2009 06:28:48 +0000 (06:28 +0000)
specify a more granular policy for cross-origin XHR access.

Patch by Aaron Boodman <aa@chromium.org> on 2009-08-19
Reviewed by David Levin.

Tests: http/tests/xmlhttprequest/origin-whitelisting-all.html
       http/tests/xmlhttprequest/origin-whitelisting-exact-match.html
       http/tests/xmlhttprequest/origin-whitelisting-https.html
       http/tests/xmlhttprequest/origin-whitelisting-ip-addresses-with-subdomains.html
       http/tests/xmlhttprequest/origin-whitelisting-ip-addresses.html
       http/tests/xmlhttprequest/origin-whitelisting-subdomains.html

* WebCore.base.exp: Export methods to manipulate origin access whitelists to enable
testing via layout tests.

* WebCore.xcodeproj/project.pbxproj: Add OriginAccessEntry.*
* GNUmakefile.am: Ditto.
* WebCore.gypi: Ditto.
* WebCore.pro: Ditto.
* WebCore.vcproj/WebCore.vcproj: Ditto.
* WebCoreSources.blk: Ditto.

* page/SecurityOrigin.h: Implement origin access whitelists.
(WebCore::originAccessMap): Static getter for access whitelists.
(WebCore::SecurityOrigin::canRequest): Modify request checking logic to check whitelists.
(WebCore::SecurityOrigin::whiteListAccessFromOrigin): Add an entry to a whitelist.
(WebCore::SecurityOrigin::resetOriginAccessWhiteLists): Clear all the whitelists.

* page/OriginAccessEntry.h: Added. An entry in an origin access whitelist.
* page/OriginAccessEntry.cpp: Ditto.

WebKit/gtk: https://bugs.webkit.org/show_bug.cgi?id=24853: Provide a way for WebKit clients to
specify a more granular policy for cross-origin XHR access.

Patch by Aaron Boodman <aa@chromium.org> on 2009-08-19
Reviewed by David Levin.

* webkit/webkitprivate.cpp:
(webkit_white_list_access_to_origin): Add API to manipulate origin access whitelists.
(webkit_reset_origin_access_white_lists): Ditto.
* webkit/webkitprivate.h: Ditto.

WebKit/mac: https://bugs.webkit.org/show_bug.cgi?id=24853: Provide a way for WebKit clients to
specify a more granular policy for cross-origin XHR access.

Patch by Aaron Boodman <aa@chromium.org> on 2009-08-19
Reviewed by David Levin.

* WebView/WebView.mm: Add SPI to manipulate origin access whitelists.
(+[WebView _whiteListAccessFromOrigin:destinationProtocol:destinationHost:allowDestinationSubdomains:]): Ditto.
(+[WebView _resetOriginAccessWhiteLists]): Ditto.
* WebView/WebViewPrivate.h: Ditto.

WebKit/qt: https://bugs.webkit.org/show_bug.cgi?id=24853: Provide a way for WebKit clients to
specify a more granular policy for cross-origin XHR access.

Patch by Aaron Boodman <aa@chromium.org> on 2009-08-19
Reviewed by David Levin.

* Api/qwebsecurityorigin.cpp: Add API to manipulate origin access whitelists.
(QWebSecurityOrigin::whiteListAccessFromOrigin): Ditto.
(QWebSecurityOrigin::resetOriginAccessWhiteLists): Ditto.
* Api/qwebsecurityorigin.h: Ditto.

WebKitTools: https://bugs.webkit.org/show_bug.cgi?id=24853: Provide a way for WebKit clients to
specify a more granular policy for cross-origin XHR access.

Patch by Aaron Boodman <aa@chromium.org> on 2009-08-19
Reviewed by David Levin.

* DumpRenderTree/LayoutTestController.cpp: Expose whiteListAccessFromOrigin() to layout tests.
(whiteListAccessFromOriginCallback): Ditto.
(LayoutTestController::staticFunctions): Ditto.
* DumpRenderTree/LayoutTestController.h: Ditto.
* DumpRenderTree/gtk/LayoutTestControllerGtk.cpp: Ditto.
(LayoutTestController::whiteListAccessToOrigin): Ditto.
* DumpRenderTree/mac/LayoutTestControllerMac.mm: Ditto.
(LayoutTestController::whiteListAccessFromOrigin): Ditto.
* DumpRenderTree/qt/jsobjects.cpp: Ditto.
(LayoutTestController::whiteListAccessFromOrigin): Ditto.
* DumpRenderTree/win/LayoutTestControllerWin.cpp: Stub out whiteListAccessFromOrigin().
(LayoutTestController::whiteListAccessFromOrigin): Ditto.
* DumpRenderTree/gtk/DumpRenderTree.cpp: Reset origin access lists before each test.
(resetWebViewToConsistentStateBeforeTesting): Ditto.
* DumpRenderTree/mac/DumpRenderTree.mm: Ditto.
(resetWebViewToConsistentStateBeforeTesting): Ditto.
* DumpRenderTree/qt/DumpRenderTree.cpp: Ditto.
(WebCore::DumpRenderTree::resetToConsistentStateBeforeTesting): Ditto.

LayoutTests: https://bugs.webkit.org/show_bug.cgi?id=24853: Provide a way for WebKit clients to
specify a more granular policy for cross-origin XHR access.

Patch by Aaron Boodman <aa@chromium.org> on 2009-08-19
Reviewed by David Levin.

* http/tests/xmlhttprequest/origin-whitelisting-all-expected.txt: Added.
* http/tests/xmlhttprequest/origin-whitelisting-all.html: Added.
* http/tests/xmlhttprequest/origin-whitelisting-exact-match-expected.txt: Added.
* http/tests/xmlhttprequest/origin-whitelisting-exact-match.html: Added.
* http/tests/xmlhttprequest/origin-whitelisting-https-expected.txt: Added.
* http/tests/xmlhttprequest/origin-whitelisting-https.html: Added.
* http/tests/xmlhttprequest/origin-whitelisting-ip-addresses-expected.txt: Added.
* http/tests/xmlhttprequest/origin-whitelisting-ip-addresses-with-subdomains-expected.txt: Added.
* http/tests/xmlhttprequest/origin-whitelisting-ip-addresses-with-subdomains.html: Added.
* http/tests/xmlhttprequest/origin-whitelisting-ip-addresses.html: Added.
* http/tests/xmlhttprequest/origin-whitelisting-subdomains-expected.txt: Added.
* http/tests/xmlhttprequest/origin-whitelisting-subdomains.html: Added.
* http/tests/xmlhttprequest/resources/origin-whitelisting-ip-address-test.html: Added.

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

46 files changed:
LayoutTests/ChangeLog
LayoutTests/http/tests/xmlhttprequest/origin-whitelisting-all-expected.txt [new file with mode: 0644]
LayoutTests/http/tests/xmlhttprequest/origin-whitelisting-all.html [new file with mode: 0644]
LayoutTests/http/tests/xmlhttprequest/origin-whitelisting-exact-match-expected.txt [new file with mode: 0644]
LayoutTests/http/tests/xmlhttprequest/origin-whitelisting-exact-match.html [new file with mode: 0644]
LayoutTests/http/tests/xmlhttprequest/origin-whitelisting-https-expected.txt [new file with mode: 0644]
LayoutTests/http/tests/xmlhttprequest/origin-whitelisting-https.html [new file with mode: 0644]
LayoutTests/http/tests/xmlhttprequest/origin-whitelisting-ip-addresses-expected.txt [new file with mode: 0644]
LayoutTests/http/tests/xmlhttprequest/origin-whitelisting-ip-addresses-with-subdomains-expected.txt [new file with mode: 0644]
LayoutTests/http/tests/xmlhttprequest/origin-whitelisting-ip-addresses-with-subdomains.html [new file with mode: 0644]
LayoutTests/http/tests/xmlhttprequest/origin-whitelisting-ip-addresses.html [new file with mode: 0644]
LayoutTests/http/tests/xmlhttprequest/origin-whitelisting-subdomains-expected.txt [new file with mode: 0644]
LayoutTests/http/tests/xmlhttprequest/origin-whitelisting-subdomains.html [new file with mode: 0644]
LayoutTests/http/tests/xmlhttprequest/resources/origin-whitelisting-ip-address-test.html [new file with mode: 0644]
LayoutTests/platform/win/Skipped
WebCore/ChangeLog
WebCore/GNUmakefile.am
WebCore/WebCore.base.exp
WebCore/WebCore.gypi
WebCore/WebCore.pro
WebCore/WebCore.vcproj/WebCore.vcproj
WebCore/WebCore.xcodeproj/project.pbxproj
WebCore/WebCoreSources.bkl
WebCore/page/OriginAccessEntry.cpp [new file with mode: 0644]
WebCore/page/OriginAccessEntry.h [new file with mode: 0644]
WebCore/page/SecurityOrigin.cpp
WebCore/page/SecurityOrigin.h
WebKit/gtk/ChangeLog
WebKit/gtk/webkit/webkitprivate.cpp
WebKit/gtk/webkit/webkitprivate.h
WebKit/mac/ChangeLog
WebKit/mac/WebView/WebView.mm
WebKit/mac/WebView/WebViewPrivate.h
WebKit/qt/Api/qwebsecurityorigin.cpp
WebKit/qt/Api/qwebsecurityorigin.h
WebKit/qt/ChangeLog
WebKitTools/ChangeLog
WebKitTools/DumpRenderTree/LayoutTestController.cpp
WebKitTools/DumpRenderTree/LayoutTestController.h
WebKitTools/DumpRenderTree/gtk/DumpRenderTree.cpp
WebKitTools/DumpRenderTree/gtk/LayoutTestControllerGtk.cpp
WebKitTools/DumpRenderTree/mac/DumpRenderTree.mm
WebKitTools/DumpRenderTree/mac/LayoutTestControllerMac.mm
WebKitTools/DumpRenderTree/qt/DumpRenderTree.cpp
WebKitTools/DumpRenderTree/qt/jsobjects.cpp
WebKitTools/DumpRenderTree/win/LayoutTestControllerWin.cpp

index 35df98ecd401d8093289f644cf095a6655ecd4c7..bac054853657a3c331aacdb7f36bd12b8c259b59 100644 (file)
@@ -1,3 +1,24 @@
+2009-08-19  Aaron Boodman  <aa@chromium.org>
+
+        Reviewed by David Levin.
+
+        https://bugs.webkit.org/show_bug.cgi?id=24853: Provide a way for WebKit clients to
+        specify a more granular policy for cross-origin XHR access.
+
+        * http/tests/xmlhttprequest/origin-whitelisting-all-expected.txt: Added.
+        * http/tests/xmlhttprequest/origin-whitelisting-all.html: Added.
+        * http/tests/xmlhttprequest/origin-whitelisting-exact-match-expected.txt: Added.
+        * http/tests/xmlhttprequest/origin-whitelisting-exact-match.html: Added.
+        * http/tests/xmlhttprequest/origin-whitelisting-https-expected.txt: Added.
+        * http/tests/xmlhttprequest/origin-whitelisting-https.html: Added.
+        * http/tests/xmlhttprequest/origin-whitelisting-ip-addresses-expected.txt: Added.
+        * http/tests/xmlhttprequest/origin-whitelisting-ip-addresses-with-subdomains-expected.txt: Added.
+        * http/tests/xmlhttprequest/origin-whitelisting-ip-addresses-with-subdomains.html: Added.
+        * http/tests/xmlhttprequest/origin-whitelisting-ip-addresses.html: Added.
+        * http/tests/xmlhttprequest/origin-whitelisting-subdomains-expected.txt: Added.
+        * http/tests/xmlhttprequest/origin-whitelisting-subdomains.html: Added.
+        * http/tests/xmlhttprequest/resources/origin-whitelisting-ip-address-test.html: Added.
+
 2009-08-19  Ryosuke Niwa  <rniwa@webkit.org>
 
         No review.
diff --git a/LayoutTests/http/tests/xmlhttprequest/origin-whitelisting-all-expected.txt b/LayoutTests/http/tests/xmlhttprequest/origin-whitelisting-all-expected.txt
new file mode 100644 (file)
index 0000000..12ba42f
--- /dev/null
@@ -0,0 +1,11 @@
+Tests the special case of whitelisting all origins.
+
+Testing: http://localhost:8000/xmlhttprequest/resources/get.txt (sync)
+PASS: PASS
+Testing: http://localhost:8000/xmlhttprequest/resources/get.txt (async)
+PASS: PASS
+Testing: http://127.0.0.1:8000/xmlhttprequest/resources/get.txt (sync)
+PASS: PASS
+Testing: http://127.0.0.1:8000/xmlhttprequest/resources/get.txt (async)
+PASS: PASS
+
diff --git a/LayoutTests/http/tests/xmlhttprequest/origin-whitelisting-all.html b/LayoutTests/http/tests/xmlhttprequest/origin-whitelisting-all.html
new file mode 100644 (file)
index 0000000..e0785e1
--- /dev/null
@@ -0,0 +1,56 @@
+<p>Tests the special case of whitelisting all origins.</p>
+
+<pre id="console"></pre>
+<script>
+layoutTestController.dumpAsText();
+layoutTestController.waitUntilDone();
+layoutTestController.whiteListAccessFromOrigin("http://127.0.0.1:8000", "http", "", true);
+layoutTestController.whiteListAccessFromOrigin("http://localhost:8000", "http", "", true);
+
+function log(message)
+{
+    document.getElementById('console').appendChild(document.createTextNode(message + '\n'));
+}
+
+function testDomain()
+{
+    var url = "http://localhost:8000/xmlhttprequest/resources/get.txt";
+    log("Testing: " + url + " (sync)");
+    var req = new XMLHttpRequest();
+    req.open("GET", url, false);
+    try {
+        req.send(null);
+        log("PASS: " + req.responseText);
+    } catch (e) {
+        log("FAIL: " + e);
+    }
+
+    log("Testing: " + url + " (async)");
+    req = new XMLHttpRequest();
+    req.open("GET", url, true);
+    req.onload = function() {
+        log("PASS: " + req.responseText);
+        testIPAddress();
+    };
+    req.onerror = function() {
+        log("FAIL: " + req.status);
+        testIPAddress();
+    };
+    req.send(null);
+}
+
+function testIPAddress()
+{
+    var iframe = document.createElement("iframe");
+    document.body.appendChild(iframe);
+    iframe.src = "http://localhost:8000/xmlhttprequest/resources/origin-whitelisting-ip-address-test.html";
+    window.addEventListener("message", function(e) {
+        if (e.data == "DONE")
+            layoutTestController.notifyDone();
+        else
+            log(e.data);
+    }, false);
+}
+
+testDomain();
+</script>
diff --git a/LayoutTests/http/tests/xmlhttprequest/origin-whitelisting-exact-match-expected.txt b/LayoutTests/http/tests/xmlhttprequest/origin-whitelisting-exact-match-expected.txt
new file mode 100644 (file)
index 0000000..b9916a3
--- /dev/null
@@ -0,0 +1,11 @@
+Tests the behavior of whitelisting origins using exact matching.
+
+Testing: http://localhost:8000/xmlhttprequest/resources/get.txt (sync)
+PASS: PASS
+Testing: http://localhost:8000/xmlhttprequest/resources/get.txt (async)
+PASS: PASS
+Testing: http://loCALhost:8000/xmlhttprequest/resources/get.txt (sync)
+PASS: PASS
+Testing: http://loCALhost:8000/xmlhttprequest/resources/get.txt (async)
+PASS: PASS
+
diff --git a/LayoutTests/http/tests/xmlhttprequest/origin-whitelisting-exact-match.html b/LayoutTests/http/tests/xmlhttprequest/origin-whitelisting-exact-match.html
new file mode 100644 (file)
index 0000000..b35e9de
--- /dev/null
@@ -0,0 +1,60 @@
+<p>Tests the behavior of whitelisting origins using exact matching.</p>
+
+<pre id="console"></pre>
+<script>
+layoutTestController.dumpAsText();
+layoutTestController.waitUntilDone();
+layoutTestController.whiteListAccessFromOrigin("http://127.0.0.1:8000", "http", "localhost", false);
+
+function log(message)
+{
+    document.getElementById('console').appendChild(document.createTextNode(message + '\n'));
+}
+
+function test(url, expectSuccess)
+{
+    log("Testing: " + url + " (sync)");
+    var req = new XMLHttpRequest();
+    req.open("GET", url, false);
+    try {
+        req.send(null);
+        log((expectSuccess ? "PASS: " : "FAIL: ") + req.responseText);
+    } catch (e) {
+        log((expectSuccess ? "FAIL: " : "PASS: ") + e);
+    }
+
+    log("Testing: " + url + " (async)");
+    req = new XMLHttpRequest();
+    req.open("GET", url, true);
+    req.onload = function() {
+        log((expectSuccess ? "PASS: " : "FAIL: ") + req.responseText);
+        nextTest();
+    };
+    req.onerror = function() {
+        log((expectSuccess ? "FAIL: " : "PASS: ") + req.status);
+        nextTest();
+    };
+    req.send(null);
+}
+
+var tests = [
+    ["http://localhost:8000/xmlhttprequest/resources/get.txt", true],
+    ["http://loCALhost:8000/xmlhttprequest/resources/get.txt", true]
+    // FIXME: Is it possible to setup the following tests?
+    // ["http://localhost:8001/xmlhttprequest/resources/get.txt", false],
+    // ["http://foo.localhost:8000/xmlhttprequest/resources/get.txt", false],
+    // ["https://localhost:8000/xmlhttprequest/resources/get.txt", false]
+];
+
+var currentTest = 0;
+
+function nextTest()
+{
+    if (currentTest < tests.length)
+        test.apply(null, tests[currentTest++]);
+    else
+        layoutTestController.notifyDone();
+}
+
+nextTest();
+</script>
diff --git a/LayoutTests/http/tests/xmlhttprequest/origin-whitelisting-https-expected.txt b/LayoutTests/http/tests/xmlhttprequest/origin-whitelisting-https-expected.txt
new file mode 100644 (file)
index 0000000..e33c4a8
--- /dev/null
@@ -0,0 +1,7 @@
+Tests that origin whitelisting for https does not match http URLs.
+
+Testing: http://localhost:8000/xmlhttprequest/resources/get.txt (sync)
+PASS: Error: NETWORK_ERR: XMLHttpRequest Exception 101
+Testing: http://localhost:8000/xmlhttprequest/resources/get.txt (async)
+PASS: 0
+
diff --git a/LayoutTests/http/tests/xmlhttprequest/origin-whitelisting-https.html b/LayoutTests/http/tests/xmlhttprequest/origin-whitelisting-https.html
new file mode 100644 (file)
index 0000000..10e606e
--- /dev/null
@@ -0,0 +1,57 @@
+<p>Tests that origin whitelisting for https does not match http URLs.</p>
+
+<pre id="console"></pre>
+<script>
+layoutTestController.dumpAsText();
+layoutTestController.waitUntilDone();
+layoutTestController.whiteListAccessFromOrigin("http://127.0.0.1:8000", "https", "localhost", false);
+
+function log(message)
+{
+    document.getElementById('console').appendChild(document.createTextNode(message + '\n'));
+}
+
+function test(url, expectSuccess)
+{
+    log("Testing: " + url + " (sync)");
+    var req = new XMLHttpRequest();
+    req.open("GET", url, false);
+    try {
+        req.send(null);
+        log((expectSuccess ? "PASS: " : "FAIL: ") + req.responseText);
+    } catch (e) {
+        log((expectSuccess ? "FAIL: " : "PASS: ") + e);
+    }
+
+    log("Testing: " + url + " (async)");
+    req = new XMLHttpRequest();
+    req.open("GET", url, true);
+    req.onload = function() {
+        log((expectSuccess ? "PASS: " : "FAIL: ") + req.responseText);
+        nextTest();
+    };
+    req.onerror = function() {
+        log((expectSuccess ? "FAIL: " : "PASS: ") + req.status);
+        nextTest();
+    };
+    req.send(null);
+}
+
+var tests = [
+    ["http://localhost:8000/xmlhttprequest/resources/get.txt", false]
+    // FIXME: Is it possible to setup the following tests?
+    // ["https://localhost:8000/xmlhttprequest/resources/get.txt", true]
+];
+
+var currentTest = 0;
+
+function nextTest()
+{
+    if (currentTest < tests.length)
+        test.apply(null, tests[currentTest++]);
+    else
+        layoutTestController.notifyDone();
+}
+
+nextTest();
+</script>
diff --git a/LayoutTests/http/tests/xmlhttprequest/origin-whitelisting-ip-addresses-expected.txt b/LayoutTests/http/tests/xmlhttprequest/origin-whitelisting-ip-addresses-expected.txt
new file mode 100644 (file)
index 0000000..0099474
--- /dev/null
@@ -0,0 +1,7 @@
+Tests origin whitelisting with IP addresses.
+
+Testing: http://127.0.0.1:8000/xmlhttprequest/resources/get.txt (sync)
+PASS: PASS
+Testing: http://127.0.0.1:8000/xmlhttprequest/resources/get.txt (async)
+PASS: PASS
+
diff --git a/LayoutTests/http/tests/xmlhttprequest/origin-whitelisting-ip-addresses-with-subdomains-expected.txt b/LayoutTests/http/tests/xmlhttprequest/origin-whitelisting-ip-addresses-with-subdomains-expected.txt
new file mode 100644 (file)
index 0000000..cde6832
--- /dev/null
@@ -0,0 +1,7 @@
+Specifying that an IP address should match subdomains doesn't make sense. This test verifies that it doesn't do anything.
+
+Testing: http://127.0.0.1:8000/xmlhttprequest/resources/get.txt (sync)
+FAIL: Error: NETWORK_ERR: XMLHttpRequest Exception 101
+Testing: http://127.0.0.1:8000/xmlhttprequest/resources/get.txt (async)
+FAIL: 0
+
diff --git a/LayoutTests/http/tests/xmlhttprequest/origin-whitelisting-ip-addresses-with-subdomains.html b/LayoutTests/http/tests/xmlhttprequest/origin-whitelisting-ip-addresses-with-subdomains.html
new file mode 100644 (file)
index 0000000..850d162
--- /dev/null
@@ -0,0 +1,22 @@
+<p>Specifying that an IP address should match subdomains doesn't make sense. This test verifies that it doesn't do anything.</p>
+<pre id="console"></pre>
+<script>
+layoutTestController.dumpAsText();
+layoutTestController.waitUntilDone();
+layoutTestController.whiteListAccessFromOrigin("http://localhost:8000", "http", "*.0.0.1", true);
+
+function log(message)
+{
+    document.getElementById('console').appendChild(document.createTextNode(message + '\n'));
+}
+
+var iframe = document.createElement("iframe");
+document.body.appendChild(iframe);
+iframe.src = "http://localhost:8000/xmlhttprequest/resources/origin-whitelisting-ip-address-test.html";
+window.addEventListener("message", function(e) {
+    if (e.data == "DONE")
+        layoutTestController.notifyDone();
+    else
+        log(e.data);
+}, false);
+</script>
diff --git a/LayoutTests/http/tests/xmlhttprequest/origin-whitelisting-ip-addresses.html b/LayoutTests/http/tests/xmlhttprequest/origin-whitelisting-ip-addresses.html
new file mode 100644 (file)
index 0000000..a3a3af7
--- /dev/null
@@ -0,0 +1,22 @@
+<p>Tests origin whitelisting with IP addresses.</p>
+<pre id="console"></pre>
+<script>
+layoutTestController.dumpAsText();
+layoutTestController.waitUntilDone();
+layoutTestController.whiteListAccessFromOrigin("http://localhost:8000", "http", "127.0.0.1", false);
+
+function log(message)
+{
+    document.getElementById('console').appendChild(document.createTextNode(message + '\n'));
+}
+
+var iframe = document.createElement("iframe");
+document.body.appendChild(iframe);
+iframe.src = "http://localhost:8000/xmlhttprequest/resources/origin-whitelisting-ip-address-test.html";
+window.addEventListener("message", function(e) {
+    if (e.data == "DONE")
+        layoutTestController.notifyDone();
+    else
+        log(e.data);
+}, false);
+</script>
diff --git a/LayoutTests/http/tests/xmlhttprequest/origin-whitelisting-subdomains-expected.txt b/LayoutTests/http/tests/xmlhttprequest/origin-whitelisting-subdomains-expected.txt
new file mode 100644 (file)
index 0000000..3e62e4e
--- /dev/null
@@ -0,0 +1,7 @@
+Tests origin whitelisting subdomain behavior.
+
+Testing: http://localhost:8000/xmlhttprequest/resources/get.txt (sync)
+PASS: PASS
+Testing: http://localhost:8000/xmlhttprequest/resources/get.txt (async)
+PASS: PASS
+
diff --git a/LayoutTests/http/tests/xmlhttprequest/origin-whitelisting-subdomains.html b/LayoutTests/http/tests/xmlhttprequest/origin-whitelisting-subdomains.html
new file mode 100644 (file)
index 0000000..61610e4
--- /dev/null
@@ -0,0 +1,59 @@
+<p>Tests origin whitelisting subdomain behavior.</p>
+
+<pre id="console"></pre>
+<script>
+layoutTestController.dumpAsText();
+layoutTestController.waitUntilDone();
+layoutTestController.whiteListAccessFromOrigin("http://127.0.0.1:8000", "http", "localhost", true);
+
+function log(message)
+{
+    document.getElementById('console').appendChild(document.createTextNode(message + '\n'));
+}
+
+function test(url, expectSuccess)
+{
+    log("Testing: " + url + " (sync)");
+    var req = new XMLHttpRequest();
+    req.open("GET", url, false);
+    try {
+        req.send(null);
+        log((expectSuccess ? "PASS: " : "FAIL: ") + req.responseText);
+    } catch (e) {
+        log((expectSuccess ? "FAIL: " : "PASS: ") + e);
+    }
+
+    log("Testing: " + url + " (async)");
+    req = new XMLHttpRequest();
+    req.open("GET", url, true);
+    req.onload = function() {
+        log((expectSuccess ? "PASS: " : "FAIL: ") + req.responseText);
+        nextTest();
+    };
+    req.onerror = function() {
+        log((expectSuccess ? "FAIL: " : "PASS: ") + req.status);
+        nextTest();
+    };
+    req.send(null);
+}
+
+var tests = [
+    ["http://localhost:8000/xmlhttprequest/resources/get.txt", true]
+    // FIXME: Is it possible to setup the following tests?
+    // ["http://foo.localhost:8000/xmlhttprequest/resources/get.txt", true]
+    // ["http://bar.foo.localhost:8000/xmlhttprequest/resources/get.txt", true]
+    // ["http://foolocalhost:8000/xmlhttprequest/resources/get.txt", false]
+];
+
+var currentTest = 0;
+
+function nextTest()
+{
+    if (currentTest < tests.length)
+        test.apply(null, tests[currentTest++]);
+    else
+        layoutTestController.notifyDone();
+}
+
+nextTest();
+</script>
diff --git a/LayoutTests/http/tests/xmlhttprequest/resources/origin-whitelisting-ip-address-test.html b/LayoutTests/http/tests/xmlhttprequest/resources/origin-whitelisting-ip-address-test.html
new file mode 100644 (file)
index 0000000..3be1d29
--- /dev/null
@@ -0,0 +1,34 @@
+<p>Tests origin whitelisting to an IP address.</p>
+<p>Intended to be run in an iframe. Notifies success/failure via postMessage().</p>
+
+<pre id="console"></pre>
+<script>
+function log(message)
+{
+    window.parent.postMessage(message, "http://127.0.0.1:8000");
+}
+
+var url = "http://127.0.0.1:8000/xmlhttprequest/resources/get.txt";
+log("Testing: " + url + " (sync)");
+var req = new XMLHttpRequest();
+req.open("GET", url, false);
+try {
+    req.send(null);
+    log("PASS: " + req.responseText);
+} catch (e) {
+    log("FAIL: " + e);
+}
+
+log("Testing: " + url + " (async)");
+req = new XMLHttpRequest();
+req.open("GET", url, true);
+req.onload = function() {
+    log("PASS: " + req.responseText);
+    log("DONE");
+};
+req.onerror = function() {
+    log("FAIL: " + req.status);
+    log("DONE");
+};
+req.send(null);
+</script>
index 8137431a4a08cdd1db347aa16f8a0724b48beb19..a904517606cb5d684d878d46a70f6918a1ff7dc7 100644 (file)
@@ -636,3 +636,12 @@ media/video-source-error.html
 
 # <http://webkit.org/b/28467>
 http/tests/loading/preload-img-test.html
+
+# Missing LayoutTestController implementation
+http/tests/xmlhttprequest/origin-whitelisting-all.html
+http/tests/xmlhttprequest/origin-whitelisting-exact-match.html
+http/tests/xmlhttprequest/origin-whitelisting-https.html
+http/tests/xmlhttprequest/origin-whitelisting-ip-addresses.html
+http/tests/xmlhttprequest/origin-whitelisting-ip-addresses-with-subdomains.html
+http/tests/xmlhttprequest/origin-whitelisting-subdomains.html
+
index dcf6c7480952726f80e6d14fde3890c149995e1d..25089d0821f779c2101390d8ae423017416b71cd 100644 (file)
@@ -1,3 +1,36 @@
+2009-08-19  Aaron Boodman  <aa@chromium.org>
+
+        Reviewed by David Levin.
+
+        https://bugs.webkit.org/show_bug.cgi?id=24853: Provide a way for WebKit clients to
+        specify a more granular policy for cross-origin XHR access.
+
+        Tests: http/tests/xmlhttprequest/origin-whitelisting-all.html
+               http/tests/xmlhttprequest/origin-whitelisting-exact-match.html
+               http/tests/xmlhttprequest/origin-whitelisting-https.html
+               http/tests/xmlhttprequest/origin-whitelisting-ip-addresses-with-subdomains.html
+               http/tests/xmlhttprequest/origin-whitelisting-ip-addresses.html
+               http/tests/xmlhttprequest/origin-whitelisting-subdomains.html
+
+        * WebCore.base.exp: Export methods to manipulate origin access whitelists to enable
+        testing via layout tests.
+
+        * WebCore.xcodeproj/project.pbxproj: Add OriginAccessEntry.*
+        * GNUmakefile.am: Ditto.
+        * WebCore.gypi: Ditto.
+        * WebCore.pro: Ditto.
+        * WebCore.vcproj/WebCore.vcproj: Ditto.
+        * WebCoreSources.blk: Ditto.
+
+        * page/SecurityOrigin.h: Implement origin access whitelists.
+        (WebCore::originAccessMap): Static getter for access whitelists.
+        (WebCore::SecurityOrigin::canRequest): Modify request checking logic to check whitelists.
+        (WebCore::SecurityOrigin::whiteListAccessFromOrigin): Add an entry to a whitelist.
+        (WebCore::SecurityOrigin::resetOriginAccessWhiteLists): Clear all the whitelists.
+
+        * page/OriginAccessEntry.h: Added. An entry in an origin access whitelist.
+        * page/OriginAccessEntry.cpp: Ditto.
+
 2009-08-19  Kevin Ollivier  <kevino@theolliviers.com>
 
         Non-precomp headers build fix.
index c43e6f8c6299740955844588b772b36aef6de29e..32ed03df515c6393dafc47f42b2086f2f178d405 100644 (file)
@@ -1300,6 +1300,8 @@ webcore_sources += \
        WebCore/page/Navigator.h \
        WebCore/page/NavigatorBase.cpp \
        WebCore/page/NavigatorBase.h \
+       WebCore/page/OriginAccessEntry.cpp \
+       WebCore/page/OriginAccessEntry.h \
        WebCore/page/Page.cpp \
        WebCore/page/Page.h \
        WebCore/page/PageGroup.cpp \
index cfbb23c605e66cb25fc69b2e70dc9df08e5f5834..90ff377685246db63b74aed585077efd2d07fb27 100644 (file)
@@ -312,8 +312,11 @@ __ZN7WebCore14ResourceHandle12releaseProxyEv
 __ZN7WebCore14ResourceHandle20forceContentSniffingEv
 __ZN7WebCore14ResourceLoader14cancelledErrorEv
 __ZN7WebCore14ResourceLoader19setShouldBufferDataEb
-__ZN7WebCore14SecurityOrigin24registerURLSchemeAsLocalERKNS_6StringE
 __ZN7WebCore14SecurityOrigin6createERKNS_4KURLE
+__ZN7WebCore14SecurityOrigin16createFromStringERKNS_6StringE
+__ZN7WebCore14SecurityOrigin24registerURLSchemeAsLocalERKNS_6StringE
+__ZN7WebCore14SecurityOrigin25whiteListAccessFromOriginERKS0_RKNS_6StringES5_b
+__ZN7WebCore14SecurityOrigin27resetOriginAccessWhiteListsEv
 __ZN7WebCore15ArchiveResource6createEN3WTF10PassRefPtrINS_12SharedBufferEEERKNS_4KURLERKNS_6StringESA_SA_RKNS_16ResourceResponseE
 __ZN7WebCore15BackForwardList10removeItemEPNS_11HistoryItemE
 __ZN7WebCore15BackForwardList10setEnabledEb
index 65110e24ebd40eaf77502f57ef0f7c627e3a1996..7c26a4610001933ae7454716de3b6179a8c5523c 100644 (file)
             'page/Navigator.h',
             'page/NavigatorBase.cpp',
             'page/NavigatorBase.h',
+            'page/OriginAccessEntry.cpp',
+            'page/OriginAccessEntry.h',
             'page/Page.cpp',
             'page/Page.h',
             'page/PageGroup.cpp',
index a8d894a1ab70815e65fcb0da49c6d587c09012cd..aba4381a09c75bd45698c45ccd40771e87810286 100644 (file)
@@ -1108,6 +1108,7 @@ SOURCES += \
     page/History.cpp \
     page/Location.cpp \
     page/MouseEventWithHitTestResults.cpp \
+    page/OriginAccessEntry.cpp \
     page/Page.cpp \
     page/PageGroup.cpp \
     page/PageGroupLoadDeferrer.cpp \
index 0a5c32c27570e739aa95e3966f6a522c0a7c9fe6..9de2133d2d3275168936ec2aa68bbdac7e8231df 100644 (file)
                                RelativePath="..\page\NavigatorBase.h"\r
                                >\r
                        </File>\r
+                       <File\r
+                               RelativePath="..\page\OriginAccessEntry.cpp"\r
+                               >\r
+                       </File>\r
+                       <File\r
+                               RelativePath="..\page\OriginAccessEntry.h"\r
+                               >\r
+                       </File>\r
                        <File\r
                                RelativePath="..\page\Page.cpp"\r
                                >\r
index c7c7365d23328fc60f8f73103a3265626a8f956c..8b345a5903d705cb9e3314466c4f20b263275be5 100644 (file)
@@ -21,6 +21,8 @@
 /* End PBXAggregateTarget section */
 
 /* Begin PBXBuildFile section */
+               0014628A103CD1DE000B20DB /* OriginAccessEntry.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 00146288103CD1DE000B20DB /* OriginAccessEntry.cpp */; };
+               0014628B103CD1DE000B20DB /* OriginAccessEntry.h in Headers */ = {isa = PBXBuildFile; fileRef = 00146289103CD1DE000B20DB /* OriginAccessEntry.h */; };
                06027CAD0B1CBFC000884B2D /* ContextMenuItem.h in Headers */ = {isa = PBXBuildFile; fileRef = 06027CAC0B1CBFC000884B2D /* ContextMenuItem.h */; settings = {ATTRIBUTES = (Private, ); }; };
                06027CB30B1CC03D00884B2D /* ContextMenuItemMac.mm in Sources */ = {isa = PBXBuildFile; fileRef = 06027CB20B1CC03D00884B2D /* ContextMenuItemMac.mm */; };
                062287840B4DB322000C34DF /* FocusDirection.h in Headers */ = {isa = PBXBuildFile; fileRef = 062287830B4DB322000C34DF /* FocusDirection.h */; settings = {ATTRIBUTES = (Private, ); }; };
 /* End PBXCopyFilesBuildPhase section */
 
 /* Begin PBXFileReference section */
+               00146288103CD1DE000B20DB /* OriginAccessEntry.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = OriginAccessEntry.cpp; sourceTree = "<group>"; };
+               00146289103CD1DE000B20DB /* OriginAccessEntry.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = OriginAccessEntry.h; sourceTree = "<group>"; };
                06027CAC0B1CBFC000884B2D /* ContextMenuItem.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; path = ContextMenuItem.h; sourceTree = "<group>"; };
                06027CB20B1CC03D00884B2D /* ContextMenuItemMac.mm */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.objcpp; path = ContextMenuItemMac.mm; sourceTree = "<group>"; };
                062287830B4DB322000C34DF /* FocusDirection.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; path = FocusDirection.h; sourceTree = "<group>"; };
                                A9C6E65D0D746694006442E9 /* Navigator.idl */,
                                E12719C90EEEC21300F61213 /* NavigatorBase.cpp */,
                                E12719C60EEEC16800F61213 /* NavigatorBase.h */,
+                               00146288103CD1DE000B20DB /* OriginAccessEntry.cpp */,
+                               00146289103CD1DE000B20DB /* OriginAccessEntry.h */,
                                65FEA86809833ADE00BED4AB /* Page.cpp */,
                                65A21467097A329100B9050A /* Page.h */,
                                9302B0BC0D79F82900C7EE83 /* PageGroup.cpp */,
                                B5C1123C102B6C4600096578 /* SQLTransactionCoordinator.h in Headers */,
                                D8B6152F1032495100C8554A /* Cookie.h in Headers */,
                                BCFA930810333193007B25D1 /* RenderOverflow.h in Headers */,
+                               0014628B103CD1DE000B20DB /* OriginAccessEntry.h in Headers */,
                        );
                        runOnlyForDeploymentPostprocessing = 0;
                };
                                9392262D1032107B006E7D5D /* JSHTMLCanvasElementCustom.cpp in Sources */,
                                9392262F10321084006E7D5D /* JSCSSRuleListCustom.cpp in Sources */,
                                B5C1123B102B6C4600096578 /* SQLTransactionCoordinator.cpp in Sources */,
+                               0014628A103CD1DE000B20DB /* OriginAccessEntry.cpp in Sources */,
                        );
                        runOnlyForDeploymentPostprocessing = 0;
                };
index a40c2b1ce270a86691e3d930c13b40fd27f15bf6..f1dca39c1ea5fbe430d8c768206a6d1c6577d02c 100644 (file)
@@ -766,6 +766,7 @@ This file contains the list of files needed to build WebCore.
         page/MouseEventWithHitTestResults.cpp
         page/Navigator.cpp
         page/NavigatorBase.cpp
+        page/OriginAccessEntry.cpp
         page/Page.cpp
         page/PageGroup.cpp
         page/PageGroupLoadDeferrer.cpp
diff --git a/WebCore/page/OriginAccessEntry.cpp b/WebCore/page/OriginAccessEntry.cpp
new file mode 100644 (file)
index 0000000..eb08a17
--- /dev/null
@@ -0,0 +1,82 @@
+/*
+ * Copyright (C) 2009 Google Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ *     * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *     * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ *     * Neither the name of Google Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "config.h"
+#include "OriginAccessEntry.h"
+
+#include "CType.h"
+#include "SecurityOrigin.h"
+
+namespace WebCore {
+    
+OriginAccessEntry::OriginAccessEntry(const String& protocol, const String& host, SubdomainSetting subdomainSetting)
+    : m_protocol(protocol.lower())
+    , m_host(host.lower())
+    , m_subdomainSettings(subdomainSetting)
+{
+    ASSERT(m_protocol == "http" || m_protocol == "https");
+    ASSERT(subdomainSetting == AllowSubdomains || subdomainSetting == DisallowSubdomains);
+
+    // Assume that any host that ends with a digit is trying to be an IP address.
+    m_hostIsIPAddress = !m_host.isEmpty() && isASCIIDigit(m_host[m_host.length() - 1]);
+}
+
+bool OriginAccessEntry::matchesOrigin(const SecurityOrigin& origin) const
+{
+    ASSERT(origin.host() == origin.host().lower());
+    ASSERT(origin.protocol() == origin.protocol().lower());
+
+    if (m_protocol != origin.protocol())
+        return false;
+    
+    // Special case: Include subdomains and empty host means "all hosts, including ip addresses".
+    if (m_subdomainSettings == AllowSubdomains && m_host.isEmpty())
+        return true;
+    
+    // Exact match.
+    if (m_host == origin.host())
+        return true;
+    
+    // Otherwise we can only match if we're matching subdomains.
+    if (m_subdomainSettings == DisallowSubdomains)
+        return false;
+    
+    // Don't try to do subdomain matching on IP addresses.
+    if (m_hostIsIPAddress)
+        return false;
+    
+    // Match subdomains.
+    if (origin.host().length() > m_host.length() && origin.host()[origin.host().length() - m_host.length() - 1] == '.' && origin.host().endsWith(m_host))
+        return true;
+    
+    return false;
+}
+    
+} // namespace WebCore
diff --git a/WebCore/page/OriginAccessEntry.h b/WebCore/page/OriginAccessEntry.h
new file mode 100644 (file)
index 0000000..767d75f
--- /dev/null
@@ -0,0 +1,61 @@
+/*
+ * Copyright (C) 2009 Google Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ *     * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *     * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ *     * Neither the name of Google Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef CrossOriginAccess_h
+#define CrossOriginAccess_h
+
+#include "PlatformString.h"
+
+namespace WebCore {
+
+class SecurityOrigin;
+
+class OriginAccessEntry {
+public:
+    enum SubdomainSetting {
+        AllowSubdomains,
+        DisallowSubdomains
+    };
+
+    // If host is empty string and SubdomainSetting is AllowSubdomains, the entry will match all domains in the specified protocol.
+    OriginAccessEntry(const String& protocol, const String& host, SubdomainSetting);
+    bool matchesOrigin(const SecurityOrigin&) const;
+    
+private:
+    String m_protocol;
+    String m_host;
+    SubdomainSetting m_subdomainSettings;
+    bool m_hostIsIPAddress;
+    
+};
+
+} // namespace WebCore
+
+#endif // CrossOriginAccess_h
index 8274e0e762ae7ba23d74429d966b1b0c6a7a357c..33ede0069ea9d67b5949db8224181dc239907ba1 100644 (file)
 #include "CString.h"
 #include "FrameLoader.h"
 #include "KURL.h"
+#include "OriginAccessEntry.h"
 #include <wtf/StdLibExtras.h>
 
 namespace WebCore {
 
+typedef Vector<OriginAccessEntry> OriginAccessWhiteList;
+typedef HashMap<String, OriginAccessWhiteList*> OriginAccessMap;
+
+static OriginAccessMap& originAccessMap()
+{
+    DEFINE_STATIC_LOCAL(OriginAccessMap, originAccessMap, ());
+    return originAccessMap;
+}
+
 static URLSchemesMap& localSchemes()
 {
     DEFINE_STATIC_LOCAL(URLSchemesMap, localSchemes, ());
@@ -198,7 +208,17 @@ bool SecurityOrigin::canRequest(const KURL& url) const
 
     // We call isSameSchemeHostPort here instead of canAccess because we want
     // to ignore document.domain effects.
-    return isSameSchemeHostPort(targetOrigin.get());
+    if (isSameSchemeHostPort(targetOrigin.get()))
+        return true;
+
+    if (OriginAccessWhiteList* list = originAccessMap().get(toString())) {
+        for (size_t i = 0; i < list->size(); ++i) {
+            if (list->at(i).matchesOrigin(*targetOrigin))
+                return true;
+        }
+    }
+
+    return false;
 }
 
 void SecurityOrigin::grantLoadLocalResources()
@@ -414,4 +434,28 @@ bool SecurityOrigin::shouldTreatURLSchemeAsNoAccess(const String& scheme)
     return noAccessSchemes().contains(scheme);
 }
 
+void SecurityOrigin::whiteListAccessFromOrigin(const SecurityOrigin& sourceOrigin, const String& destinationProtocol, const String& destinationDomains, bool allowDestinationSubdomains)
+{
+    ASSERT(isMainThread());
+    ASSERT(!sourceOrigin.isEmpty());
+    if (sourceOrigin.isEmpty())
+        return;
+
+    String sourceString = sourceOrigin.toString();
+    OriginAccessWhiteList* list = originAccessMap().get(sourceString);
+    if (!list) {
+        list = new OriginAccessWhiteList;
+        originAccessMap().set(sourceString, list);
+    }
+    list->append(OriginAccessEntry(destinationProtocol, destinationDomains, allowDestinationSubdomains ? OriginAccessEntry::AllowSubdomains : OriginAccessEntry::DisallowSubdomains));
+}
+
+void SecurityOrigin::resetOriginAccessWhiteLists()
+{
+    ASSERT(isMainThread());
+    OriginAccessMap& map = originAccessMap();
+    deleteAllValues(map);
+    map.clear();
+}
+
 } // namespace WebCore
index 335ed2892fec8007930a3821b4e6a3409f374f8c..cc2acdd2e5ad3d4732feeb08bcb93a59cf36357a 100644 (file)
@@ -141,6 +141,9 @@ namespace WebCore {
         static void registerURLSchemeAsNoAccess(const String&);
         static bool shouldTreatURLSchemeAsNoAccess(const String&);
 
+        static void whiteListAccessFromOrigin(const SecurityOrigin& sourceOrigin, const String& destinationProtocol, const String& destinationDomains, bool allowDestinationSubdomains);
+        static void resetOriginAccessWhiteLists();
+
     private:
         explicit SecurityOrigin(const KURL&);
         explicit SecurityOrigin(const SecurityOrigin*);
index 4fa1ab65d9a7bd31d4db71f2a9fb2d3be19df411..e097e7a63c1db1aea73b8666d5067d65c701a32f 100644 (file)
@@ -1,3 +1,15 @@
+2009-08-19  Aaron Boodman  <aa@chromium.org>
+
+        Reviewed by David Levin.
+
+        https://bugs.webkit.org/show_bug.cgi?id=24853: Provide a way for WebKit clients to
+        specify a more granular policy for cross-origin XHR access.
+
+        * webkit/webkitprivate.cpp:
+        (webkit_white_list_access_to_origin): Add API to manipulate origin access whitelists.
+        (webkit_reset_origin_access_white_lists): Ditto.
+        * webkit/webkitprivate.h: Ditto.
+
 2009-08-18  Xan Lopez  <xlopez@igalia.com>
 
         Rubber-stamped by Holger Freyther.
index 755b4d3e8cfd3eedb3e6f97ce98718e3611cd96e..4b3c65c45708f84313745e3fd2c8cc01e3d06414 100644 (file)
@@ -37,6 +37,7 @@
 #include "ResourceHandleClient.h"
 #include "ResourceHandleInternal.h"
 #include <runtime/InitializeThreading.h>
+#include "SecurityOrigin.h"
 
 #if ENABLE(DATABASE)
 #include "DatabaseTracker.h"
@@ -178,3 +179,13 @@ void webkit_init()
     soup_session_add_feature(session, sniffer);
     g_object_unref(sniffer);
 }
+
+void webkit_white_list_access_to_origin(const gchar* sourceOrigin, const gchar* destinationProtocol, const gchar* destinationHost, bool allowDestinationSubdomains)
+{
+    SecurityOrigin::whiteListAccessToOrigin(SecurityOrigin::createFromString(sourceOrigin), destinationProtocol, destinationHost, allowDestinationSubdomains);
+}
+
+void webkit_reset_origin_access_white_lists()
+{
+    SecurityOrigin::resetOriginAccessWhiteLists();
+}
index de812222baef5409f17f4c4290a56be5428de002..cf89f712ac8963f480d5f89d6bd2e7367516fbb1 100644 (file)
@@ -253,6 +253,12 @@ extern "C" {
 
     WEBKIT_API unsigned int
     webkit_worker_thread_count();
+    
+    WEBKIT API void
+    webkit_white_list_access_to_origin(const gchar* sourceOrigin, const gchar* destinationProtocol, const gchar* destinationHost, bool allowDestinationSubdomains);
+    
+    WEBKIT API void
+    webkit_reset_origin_access_white_lists();
 }
 
 #endif
index 5335efb3fde810fc7f33df1c6ac20c1d085a087c..c51d9f32f305f68035e37ef63d41132e2e3a9d1f 100644 (file)
@@ -1,3 +1,15 @@
+2009-08-19  Aaron Boodman  <aa@chromium.org>
+
+        Reviewed by David Levin.
+
+        https://bugs.webkit.org/show_bug.cgi?id=24853: Provide a way for WebKit clients to
+        specify a more granular policy for cross-origin XHR access.
+
+        * WebView/WebView.mm: Add SPI to manipulate origin access whitelists.
+        (+[WebView _whiteListAccessFromOrigin:destinationProtocol:destinationHost:allowDestinationSubdomains:]): Ditto.
+        (+[WebView _resetOriginAccessWhiteLists]): Ditto.
+        * WebView/WebViewPrivate.h: Ditto.
+
 2009-08-18  Anders Carlsson  <andersca@apple.com>
 
         Reviewed by Adele Peterson.
index 3a3cb590939c49ffa2f5da1ee6ccb5192db28e19..f16b275ffcd8d644cf0fd0f045a1c6775a88d346 100644 (file)
@@ -2092,6 +2092,15 @@ static inline IMP getMethod(id o, SEL s)
     return _private ? _private->insertionPasteboard : nil;
 }
 
++ (void)_whiteListAccessFromOrigin:(NSString *)sourceOrigin destinationProtocol:(NSString *)destinationProtocol destinationHost:(NSString *)destinationHost allowDestinationSubdomains:(BOOL)allowDestinationSubdomains
+{
+    SecurityOrigin::whiteListAccessFromOrigin(*SecurityOrigin::createFromString(sourceOrigin), destinationProtocol, destinationHost, allowDestinationSubdomains);
+}
+
++(void)_resetOriginAccessWhiteLists
+{
+    SecurityOrigin::resetOriginAccessWhiteLists();
+}
 
 - (void)_updateActiveState
 {
index 362b2e689a009e3bd5b97c8cdc6abe3a50c0089c..6c472d622fa6238f28f07d542abd434582da0c06 100644 (file)
@@ -443,6 +443,15 @@ Could be worth adding to the API.
 // Which pasteboard text is coming from in editing delegate methods such as shouldInsertNode.
 - (NSPasteboard *)_insertionPasteboard;
 
+// Whitelists access from an origin (sourceOrigin) to a set of one or more origins described by the parameters:
+// - destinationProtocol: The protocol to grant access to.
+// - destinationHost: The host to grant access to.
+// - allowDestinationSubdomains: If host is a domain, setting this to YES will whitelist host and all its subdomains, recursively.
++ (void)_whiteListAccessFromOrigin:(NSString *)sourceOrigin destinationProtocol:(NSString *)destinationProtocol destinationHost:(NSString *)destinationHost allowDestinationSubdomains:(BOOL)allowDestinationSubdomains;
+
+// Removes all white list entries created with _whiteListAccessFromOrigin.
++ (void)_resetOriginAccessWhiteLists;
+
 @end
 
 @interface WebView (WebViewPrintingPrivate)
index b3005c288a0e3ba13c771fdb223e6a0fac4e1b82..fce9a993bf7add2e99820283bd47f4f6bccdcd67 100644 (file)
@@ -235,3 +235,12 @@ QStringList QWebSecurityOrigin::localSchemes()
     return list;
 }
 
+void QWebSecurityOrigin::whiteListAccessFromOrigin(const QString& sourceOrigin, const QString& destinationProtocol, const QString& destinationHost, bool allowDestinationSubdomains)
+{
+    SecurityOrigin::whiteListAccessFromOrigin(sourceOrigin, destinationProtocol, destinationHost, allowDestinationSubdomains);
+}
+
+void QWebSecurityOrigin::resetOriginAccessWhiteLists()
+{
+    SecurityOrigin::resetOriginAccessWhiteLists();
+}
index 16f8bc1d4d2e4f309c71b2e57263eb68d9ffd841..0556b89567f9184d81db657afa7064f8fd76513e 100644 (file)
@@ -40,6 +40,8 @@ public:
     static void addLocalScheme(const QString& scheme);
     static void removeLocalScheme(const QString& scheme);
     static QStringList localSchemes();
+    static void whiteListAccessFromOrigin(const QString& sourceOrigin, const QString& destinationProtocol, const QString& destinationHost, bool allowDestinationSubdomains);
+    static void clearOriginAccessWhiteLists();
 
     ~QWebSecurityOrigin();
 
index c5147edce094dcbccfc11d3b862a633d8a9eb8cc..28f5b62cebb739bfc0fe341f81e6943bf7b49788 100644 (file)
@@ -1,3 +1,15 @@
+2009-08-19  Aaron Boodman  <aa@chromium.org>
+
+        Reviewed by David Levin.
+
+        https://bugs.webkit.org/show_bug.cgi?id=24853: Provide a way for WebKit clients to
+        specify a more granular policy for cross-origin XHR access.
+
+        * Api/qwebsecurityorigin.cpp: Add API to manipulate origin access whitelists.
+        (QWebSecurityOrigin::whiteListAccessFromOrigin): Ditto.
+        (QWebSecurityOrigin::resetOriginAccessWhiteLists): Ditto.
+        * Api/qwebsecurityorigin.h: Ditto.
+
 2009-08-18  Markus Goetz <Markus.Goetz@nokia.com>
 
         Reviwed by Ariya Hidayat.
index d13c38f7b325ca5ce48dba6259a24cf9abe79afa..a97df78aa66c3396b0811d83952354c280593cf2 100644 (file)
@@ -1,3 +1,29 @@
+2009-08-19  Aaron Boodman  <aa@chromium.org>
+
+        Reviewed by David Levin.
+
+        https://bugs.webkit.org/show_bug.cgi?id=24853: Provide a way for WebKit clients to
+        specify a more granular policy for cross-origin XHR access.
+
+        * DumpRenderTree/LayoutTestController.cpp: Expose whiteListAccessFromOrigin() to layout tests.
+        (whiteListAccessFromOriginCallback): Ditto.
+        (LayoutTestController::staticFunctions): Ditto.
+        * DumpRenderTree/LayoutTestController.h: Ditto.
+        * DumpRenderTree/gtk/LayoutTestControllerGtk.cpp: Ditto.
+        (LayoutTestController::whiteListAccessToOrigin): Ditto.
+        * DumpRenderTree/mac/LayoutTestControllerMac.mm: Ditto.
+        (LayoutTestController::whiteListAccessFromOrigin): Ditto.
+        * DumpRenderTree/qt/jsobjects.cpp: Ditto.
+        (LayoutTestController::whiteListAccessFromOrigin): Ditto.
+        * DumpRenderTree/win/LayoutTestControllerWin.cpp: Stub out whiteListAccessFromOrigin().
+        (LayoutTestController::whiteListAccessFromOrigin): Ditto.
+        * DumpRenderTree/gtk/DumpRenderTree.cpp: Reset origin access lists before each test.
+        (resetWebViewToConsistentStateBeforeTesting): Ditto.
+        * DumpRenderTree/mac/DumpRenderTree.mm: Ditto.
+        (resetWebViewToConsistentStateBeforeTesting): Ditto.
+        * DumpRenderTree/qt/DumpRenderTree.cpp: Ditto.
+        (WebCore::DumpRenderTree::resetToConsistentStateBeforeTesting): Ditto.
+
 2009-08-19  Mark Rowe  <mrowe@apple.com>
 
         Rubber-stamped by Dan Bernstein.
index 2b070adc28fbef16877d4639476340cdf4cf2117..2ace7dca64e7db6ce355be0b2fd789422235ba38 100644 (file)
@@ -874,6 +874,24 @@ static JSValueRef waitForPolicyDelegateCallback(JSContextRef context, JSObjectRe
     return JSValueMakeUndefined(context);
 }
 
+static JSValueRef whiteListAccessFromOriginCallback(JSContextRef context, JSObjectRef, JSObjectRef thisObject, size_t argumentCount, const JSValueRef arguments[], JSValueRef* exception)
+{
+    if (argumentCount != 4)
+        return JSValueMakeUndefined(context);
+
+    JSRetainPtr<JSStringRef> sourceOrigin(Adopt, JSValueToStringCopy(context, arguments[0], exception));
+    ASSERT(!*exception);
+    JSRetainPtr<JSStringRef> destinationProtocol(Adopt, JSValueToStringCopy(context, arguments[1], exception));
+    ASSERT(!*exception);
+    JSRetainPtr<JSStringRef> destinationHost(Adopt, JSValueToStringCopy(context, arguments[2], exception));
+    ASSERT(!*exception);
+    bool allowDestinationSubdomains = JSValueToBoolean(context, arguments[3]);
+
+    LayoutTestController* controller = static_cast<LayoutTestController*>(JSObjectGetPrivate(thisObject));
+    controller->whiteListAccessFromOrigin(sourceOrigin.get(), destinationProtocol.get(), destinationHost.get(), allowDestinationSubdomains);
+    return JSValueMakeUndefined(context);
+}
+
 // Static Values
 
 static JSValueRef getGlobalFlagCallback(JSContextRef context, JSObjectRef thisObject, JSStringRef propertyName, JSValueRef* exception)
@@ -1021,6 +1039,7 @@ JSStaticFunction* LayoutTestController::staticFunctions()
         { "waitForPolicyDelegate", waitForPolicyDelegateCallback, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete },
         { "waitUntilDone", waitUntilDoneCallback, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete },
         { "windowCount", windowCountCallback, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete },
+        { "whiteListAccessFromOrigin", whiteListAccessFromOriginCallback, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete },
         { 0, 0, 0 }
     };
 
index c7b48e8587205c280181240ea738b473d89a9b00..800914ed6e89f78a5cb5cda41f8e4c51cf686a21 100644 (file)
@@ -179,7 +179,9 @@ public:
     bool pauseAnimationAtTimeOnElementWithId(JSStringRef animationName, double time, JSStringRef elementId);
     bool pauseTransitionAtTimeOnElementWithId(JSStringRef propertyName, double time, JSStringRef elementId);
     unsigned numberOfActiveAnimations() const;
-    
+
+    void whiteListAccessFromOrigin(JSStringRef sourceOrigin, JSStringRef destinationProtocol, JSStringRef destinationHost, bool allowDestinationSubdomains);
+
 private:
     bool m_dumpAsText;
     bool m_dumpAsPDF;
index 7450cfb3d7bf448b866018ada16a6e51ecc1cd45..ab0e5f06f040dec4fb9fd1b15cf90c7aa7957cd9 100644 (file)
@@ -62,6 +62,7 @@ extern void webkit_web_settings_add_extra_plugin_directory(WebKitWebView* view,
 extern gchar* webkit_web_frame_get_response_mime_type(WebKitWebFrame* frame);
 extern void webkit_web_frame_clear_main_frame_name(WebKitWebFrame* frame);
 extern void webkit_web_view_set_group_name(WebKitWebView* view, const gchar* groupName);
+extern void webkit_reset_origin_access_white_lists();
 }
 
 volatile bool done;
@@ -280,6 +281,8 @@ static void resetWebViewToConsistentStateBeforeTesting()
 
     WebKitWebInspector* inspector = webkit_web_view_get_inspector(webView);
     g_object_set(G_OBJECT(inspector), "javascript-profiling-enabled", FALSE, NULL);
+
+    webkit_reset_origin_access_white_lists();
 }
 
 void dump()
index 388fbeda4b10ccac0d4fb719d478ea3d280b5c71..4a9951d6c2416d79b9315fce88b2f67744efd791 100644 (file)
@@ -49,6 +49,7 @@ bool webkit_web_frame_pause_transition(WebKitWebFrame* frame, const gchar* name,
 unsigned int webkit_web_frame_number_of_active_animations(WebKitWebFrame* frame);
 void webkit_application_cache_set_maximum_size(unsigned long long size);
 unsigned int webkit_worker_thread_count(void);
+void webkit_white_list_access_to_origin(const gchar* sourceOrigin, const gchar* destinationProtocol, const gchar* destinationHost, bool allowDestinationSubdomains);
 }
 
 LayoutTestController::~LayoutTestController()
@@ -169,6 +170,14 @@ void LayoutTestController::waitForPolicyDelegate()
     setWaitToDump(true);
 }
 
+void LayoutTestController::whiteListAccessToOrigin(JSStringRef sourceOrigin, JSStringRef protocol, JSStringRef host, bool includeSubdomains)
+{
+    gchar* sourceOriginGChar = JSStringCopyUTF8CString(sourceOrigin);
+    gchar* protocolGChar = JSStringCopyUTF8CString(protocol);
+    gchar* hostGChar = JSStringCopyUTF8CString(host);
+    webkit_white_list_access_to_origin(sourceOriginGChar, protocolGChar, hostGChar, includeSubdomains);
+}
+
 void LayoutTestController::setMainFrameIsFirstResponder(bool flag)
 {
     // FIXME: implement
index 0acff7777a6484baf0865818feb9a800eef36e1b..8055722fd7bb3e278ef00376697727cab90ae7c1 100644 (file)
@@ -1082,6 +1082,7 @@ static void resetWebViewToConsistentStateBeforeTesting()
     [[[mainFrame webView] inspector] setJavaScriptProfilingEnabled:NO];
 
     [WebView _setUsesTestModeFocusRingColor:YES];
+    [WebView _resetOriginAccessWhiteLists];
 }
 
 static void runTest(const string& testPathOrURL)
index d31cd8d33408e27af2ebe4fae939146572f07782..b39cf4793243e09e9184b8e571d771d603e07dc6 100644 (file)
@@ -443,3 +443,14 @@ void LayoutTestController::waitForPolicyDelegate()
     [policyDelegate setControllerToNotifyDone:this];
     [[mainFrame webView] setPolicyDelegate:policyDelegate];
 }
+
+void LayoutTestController::whiteListAccessFromOrigin(JSStringRef sourceOrigin, JSStringRef destinationProtocol, JSStringRef destinationHost, bool allowDestinationSubdomains)
+{
+    RetainPtr<CFStringRef> sourceOriginCF(AdoptCF, JSStringCopyCFString(kCFAllocatorDefault, sourceOrigin));
+    NSString *sourceOriginNS = (NSString *)sourceOriginCF.get();
+    RetainPtr<CFStringRef> protocolCF(AdoptCF, JSStringCopyCFString(kCFAllocatorDefault, destinationProtocol));
+    NSString *destinationProtocolNS = (NSString *)protocolCF.get();
+    RetainPtr<CFStringRef> hostCF(AdoptCF, JSStringCopyCFString(kCFAllocatorDefault, destinationHost));
+    NSString *destinationHostNS = (NSString *)hostCF.get();
+    [WebView _whiteListAccessFromOrigin:sourceOriginNS destinationProtocol:destinationProtocolNS destinationHost:destinationHostNS allowDestinationSubdomains:allowDestinationSubdomains];
+}
index 167a4c56259377b4f3531d678033b5c1d0de5673..5e309f4f4bfbc044e67f63b8ce64f4f6fc02ede0 100644 (file)
@@ -218,6 +218,7 @@ void DumpRenderTree::resetToConsistentStateBeforeTesting()
     //WorkQueue::shared()->setFrozen(false);
 
     m_controller->reset();
+    QWebSecurityOrigin::resetOriginAccessWhiteLists();
 }
 
 void DumpRenderTree::open(const QUrl& aurl)
index c9e7b849e30bed88a7df4521e50cd6fbcc2e9c2a..4bef3b96753718a5551aa4e03bdfe40a5d04a647 100644 (file)
@@ -337,6 +337,11 @@ void LayoutTestController::clearAllDatabases()
     QWebDatabase::removeAllDatabases();
 }
 
+void LayoutTestController::whiteListAccessFromOrigin(const QString& sourceOrigin, const QString& destinationProtocol, const QString& destinationHost, bool allowDestinationSubdomains)
+{
+    SecurityOrigin::whiteListAccessFromOrigin(sourceOrigin, destinationProtocol, destinationHost, allowDestinationSubdomains);
+}
+
 EventSender::EventSender(QWebPage *parent)
     : QObject(parent)
 {
index 574344ff13d728a008b1058ca14422afba0d020e..383b0067065765b0c81a4547e46f659eefabe5cb 100644 (file)
@@ -816,3 +816,8 @@ unsigned LayoutTestController::numberOfActiveAnimations() const
 
     return number;
 }
+
+void LayoutTestController::whiteListAccessFromOrigin(JSStringRef sourceOrigin, JSStringRef destinationProtocol, JSStringRef destinationHost, bool allowDestinationSubdomains)
+{
+    printf("LayoutTestController::whiteListAccessFromOrigin not implemented\n");
+}