From e5febe6eca016a19d10a6d2331364ba5970fbdf5 Mon Sep 17 00:00:00 2001 From: Phil Ames Date: Mon, 27 Aug 2012 15:46:24 -0400 Subject: [PATCH] Bug 690168. Implement the 'Allow-From' directive for X-Frame-Options. r=bzbarsky --- .../base/test/file_x-frame-options_main.html | 2 + .../base/test/file_x-frame-options_page.sjs | 6 +++ content/base/test/test_x-frame-options.html | 10 ++++ docshell/base/nsDSURIContentListener.cpp | 33 +++++++++--- dom/browser-element/mochitest/Makefile.in | 5 ++ .../browserElement_XFrameOptionsAllowFrom.js | 53 +++++++++++++++++++ ...browserElement_XFrameOptionsAllowFrom.html | 43 +++++++++++++++ ..._browserElement_XFrameOptionsAllowFrom.sjs | 16 ++++++ ...Element_inproc_XFrameOptionsAllowFrom.html | 13 +++++ ...serElement_oop_XFrameOptionsAllowFrom.html | 13 +++++ 10 files changed, 188 insertions(+), 6 deletions(-) create mode 100644 dom/browser-element/mochitest/browserElement_XFrameOptionsAllowFrom.js create mode 100644 dom/browser-element/mochitest/file_browserElement_XFrameOptionsAllowFrom.html create mode 100644 dom/browser-element/mochitest/file_browserElement_XFrameOptionsAllowFrom.sjs create mode 100644 dom/browser-element/mochitest/test_browserElement_inproc_XFrameOptionsAllowFrom.html create mode 100644 dom/browser-element/mochitest/test_browserElement_oop_XFrameOptionsAllowFrom.html diff --git a/content/base/test/file_x-frame-options_main.html b/content/base/test/file_x-frame-options_main.html index e18f74613d4d..6bc1b5f5ee64 100644 --- a/content/base/test/file_x-frame-options_main.html +++ b/content/base/test/file_x-frame-options_main.html @@ -19,6 +19,8 @@ window.addEventListener('load', parent.testFramesLoaded, false);


+
+
diff --git a/content/base/test/file_x-frame-options_page.sjs b/content/base/test/file_x-frame-options_page.sjs index dc7b3c85f4b4..1a901c8df8be 100644 --- a/content/base/test/file_x-frame-options_page.sjs +++ b/content/base/test/file_x-frame-options_page.sjs @@ -26,6 +26,12 @@ function handleRequest(request, response) else if (query['xfo'] == "mixedpolicy") { response.setHeader("X-Frame-Options", "DENY,SAMEORIGIN", false); } + else if (query['xfo'] == "afa") { + response.setHeader("X-Frame-Options", "ALLOW-FROM http://mochi.test:8888/", false); + } + else if (query['xfo'] == "afd") { + response.setHeader("X-Frame-Options", "ALLOW-FROM http://example.com/", false); + } // from the test harness we'll be checking for the presence of this element // to test if the page loaded diff --git a/content/base/test/test_x-frame-options.html b/content/base/test/test_x-frame-options.html index c09a0de82ebd..4da524a54994 100644 --- a/content/base/test/test_x-frame-options.html +++ b/content/base/test/test_x-frame-options.html @@ -108,6 +108,16 @@ var testFramesLoaded = function() { var test10 = frame.contentDocument.getElementById("test"); is(test10, null, "test mixedpolicy"); + // iframe from different origin, allow-from: this origin - should load + frame = harness.contentDocument.getElementById("allow-from-allow"); + var test11 = frame.contentDocument.getElementById("test").textContent; + is(test11, "allow-from-allow", "test allow-from-allow"); + + // iframe from different origin, with allow-from: other - should not load + frame = harness.contentDocument.getElementById("allow-from-deny"); + var test12 = frame.contentDocument.getElementById("test"); + is(test12, null, "test allow-from-deny"); + // call tests to check principal comparison, e.g. a document can open a window // to a data: or javascript: document which frames an // X-Frame-Options: SAMEORIGIN document and the frame should load diff --git a/docshell/base/nsDSURIContentListener.cpp b/docshell/base/nsDSURIContentListener.cpp index 450464f739d1..0695a612e6aa 100644 --- a/docshell/base/nsDSURIContentListener.cpp +++ b/docshell/base/nsDSURIContentListener.cpp @@ -11,6 +11,7 @@ #include "nsDocShellCID.h" #include "nsIWebNavigationInfo.h" #include "nsIDOMWindow.h" +#include "nsNetUtil.h" #include "nsAutoPtr.h" #include "nsIHttpChannel.h" #include "nsIScriptSecurityManager.h" @@ -258,9 +259,15 @@ nsDSURIContentListener::SetParentContentListener(nsIURIContentListener* bool nsDSURIContentListener::CheckOneFrameOptionsPolicy(nsIRequest *request, const nsAString& policy) { - // return early if header does not have one of the two values with meaning + static const char allowFrom[] = "allow-from "; + const PRUint32 allowFromLen = ArrayLength(allowFrom) - 1; + bool isAllowFrom = + StringHead(policy, allowFromLen).LowerCaseEqualsLiteral(allowFrom); + + // return early if header does not have one of the values with meaning if (!policy.LowerCaseEqualsLiteral("deny") && - !policy.LowerCaseEqualsLiteral("sameorigin")) + !policy.LowerCaseEqualsLiteral("sameorigin") && + !isAllowFrom) return true; nsCOMPtr httpChannel = do_QueryInterface(request); @@ -342,18 +349,32 @@ bool nsDSURIContentListener::CheckOneFrameOptionsPolicy(nsIRequest *request, return false; } + topDoc = do_GetInterface(curDocShellItem); + nsCOMPtr topUri; + topDoc->NodePrincipal()->GetURI(getter_AddRefs(topUri)); + nsCOMPtr uri; + // If the X-Frame-Options value is SAMEORIGIN, then the top frame in the // parent chain must be from the same origin as this document. if (policy.LowerCaseEqualsLiteral("sameorigin")) { - nsCOMPtr uri; httpChannel->GetURI(getter_AddRefs(uri)); - topDoc = do_GetInterface(curDocShellItem); - nsCOMPtr topUri; - topDoc->NodePrincipal()->GetURI(getter_AddRefs(topUri)); rv = ssm->CheckSameOriginURI(uri, topUri, true); if (NS_FAILED(rv)) return false; /* wasn't same-origin */ } + + // If the X-Frame-Options value is "allow-from [uri]", then the top + // frame in the parent chain must be from that origin + if (isAllowFrom) { + rv = NS_NewURI(getter_AddRefs(uri), + Substring(policy, allowFromLen)); + if (NS_FAILED(rv)) + return false; + + rv = ssm->CheckSameOriginURI(uri, topUri, true); + if (NS_FAILED(rv)) + return false; + } } return true; diff --git a/dom/browser-element/mochitest/Makefile.in b/dom/browser-element/mochitest/Makefile.in index fdb5d62209f9..38a35fcdd405 100644 --- a/dom/browser-element/mochitest/Makefile.in +++ b/dom/browser-element/mochitest/Makefile.in @@ -63,6 +63,10 @@ MOCHITEST_FILES = \ browserElement_XFrameOptionsSameOrigin.js \ test_browserElement_inproc_XFrameOptionsSameOrigin.html \ file_browserElement_XFrameOptionsSameOrigin.html \ + browserElement_XFrameOptionsAllowFrom.js \ + test_browserElement_inproc_XFrameOptionsAllowFrom.html \ + file_browserElement_XFrameOptionsAllowFrom.html \ + file_browserElement_XFrameOptionsAllowFrom.sjs \ browserElement_Alert.js \ test_browserElement_inproc_Alert.html \ browserElement_AlertInFrame.js \ @@ -154,6 +158,7 @@ MOCHITEST_FILES += \ test_browserElement_oop_XFrameOptions.html \ test_browserElement_oop_XFrameOptionsDeny.html \ test_browserElement_oop_XFrameOptionsSameOrigin.html \ + test_browserElement_oop_XFrameOptionsAllowFrom.html \ test_browserElement_oop_Alert.html \ test_browserElement_oop_AlertInFrame.html \ test_browserElement_oop_TargetTop.html \ diff --git a/dom/browser-element/mochitest/browserElement_XFrameOptionsAllowFrom.js b/dom/browser-element/mochitest/browserElement_XFrameOptionsAllowFrom.js new file mode 100644 index 000000000000..764ba833ea86 --- /dev/null +++ b/dom/browser-element/mochitest/browserElement_XFrameOptionsAllowFrom.js @@ -0,0 +1,53 @@ +/* Any copyright is dedicated to the public domain. + http://creativecommons.org/publicdomain/zero/1.0/ */ + +// Bug 690168 - Support Allow-From notation for X-Frame-Options header. +"use strict"; + +SimpleTest.waitForExplicitFinish(); + +var initialScreenshot = null; + +function runTest() { + browserElementTestHelpers.setEnabledPref(true); + browserElementTestHelpers.addPermission(); + var count = 0; + + var iframe = document.createElement('iframe'); + iframe.mozbrowser = true; + iframe.height = '1000px'; + + // The innermost page we load will fire an alert when it successfully loads. + iframe.addEventListener('mozbrowsershowmodalprompt', function(e) { + switch (e.detail.message) { + case 'step 1': + // Make the page wait for us to unblock it (which we do after we finish + // taking the screenshot). + e.preventDefault(); + + iframe.getScreenshot().onsuccess = function(sshot) { + if (initialScreenshot == null) + initialScreenshot = sshot.target.result; + e.detail.unblock(); + }; + break; + case 'step 2': + ok(false, 'cross origin page loaded'); + break; + case 'finish': + // The page has now attempted to load the X-Frame-Options page; take + // another screenshot. + iframe.getScreenshot().onsuccess = function(sshot) { + is(sshot.target.result, initialScreenshot, "Screenshots should be identical"); + SimpleTest.finish(); + }; + break; + } + }); + + document.body.appendChild(iframe); + + iframe.src = 'http://example.com/tests/dom/browser-element/mochitest/file_browserElement_XFrameOptionsAllowFrom.html'; +} + +runTest(); diff --git a/dom/browser-element/mochitest/file_browserElement_XFrameOptionsAllowFrom.html b/dom/browser-element/mochitest/file_browserElement_XFrameOptionsAllowFrom.html new file mode 100644 index 000000000000..b54247fe2059 --- /dev/null +++ b/dom/browser-element/mochitest/file_browserElement_XFrameOptionsAllowFrom.html @@ -0,0 +1,43 @@ + + + + + + + + + diff --git a/dom/browser-element/mochitest/file_browserElement_XFrameOptionsAllowFrom.sjs b/dom/browser-element/mochitest/file_browserElement_XFrameOptionsAllowFrom.sjs new file mode 100644 index 000000000000..4a5dbaaced4a --- /dev/null +++ b/dom/browser-element/mochitest/file_browserElement_XFrameOptionsAllowFrom.sjs @@ -0,0 +1,16 @@ +function handleRequest(request, response) +{ + var content = 'step 1'; + if (request.queryString == "iframe1") { + response.setHeader("X-Frame-Options", "Allow-From http://mochi.test:8888/") + content = 'finish'; + } else { + response.setHeader("X-Frame-Options", "Allow-From http://example.com") + } + + response.setHeader("Content-Type", "text/html", false); + + // Tests rely on this page not being entirely blank, because they take + // screenshots to determine whether this page was loaded. + response.write("XFrameOptions test"); +} diff --git a/dom/browser-element/mochitest/test_browserElement_inproc_XFrameOptionsAllowFrom.html b/dom/browser-element/mochitest/test_browserElement_inproc_XFrameOptionsAllowFrom.html new file mode 100644 index 000000000000..801c7879f149 --- /dev/null +++ b/dom/browser-element/mochitest/test_browserElement_inproc_XFrameOptionsAllowFrom.html @@ -0,0 +1,13 @@ + + + + Test for Bug 690168 + + + + + + + + diff --git a/dom/browser-element/mochitest/test_browserElement_oop_XFrameOptionsAllowFrom.html b/dom/browser-element/mochitest/test_browserElement_oop_XFrameOptionsAllowFrom.html new file mode 100644 index 000000000000..801c7879f149 --- /dev/null +++ b/dom/browser-element/mochitest/test_browserElement_oop_XFrameOptionsAllowFrom.html @@ -0,0 +1,13 @@ + + + + Test for Bug 690168 + + + + + + + +