Author: awiner
Date: Wed Mar 25 23:45:04 2009
New Revision: 758466
URL: http://svn.apache.org/viewvc?rev=758466&view=rev
Log:
Add non-dangerous version of
SanitizedRenderingContentRewriter.bypassSanitization().
Now doesn't only support "bypass-for-me-and-all-children"; also supports
"bypass-just-for-me".
And supports preserving this status across cloneNode() calls.
Modified:
incubator/shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/render/SanitizedRenderingContentRewriter.java
incubator/shindig/trunk/java/gadgets/src/test/java/org/apache/shindig/gadgets/render/SanitizedRenderingContentRewriterTest.java
Modified:
incubator/shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/render/SanitizedRenderingContentRewriter.java
URL:
http://svn.apache.org/viewvc/incubator/shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/render/SanitizedRenderingContentRewriter.java?rev=758466&r1=758465&r2=758466&view=diff
==============================================================================
---
incubator/shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/render/SanitizedRenderingContentRewriter.java
(original)
+++
incubator/shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/render/SanitizedRenderingContentRewriter.java
Wed Mar 25 23:45:04 2009
@@ -41,6 +41,7 @@
import org.w3c.dom.NamedNodeMap;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;
+import org.w3c.dom.UserDataHandler;
import java.io.IOException;
import java.lang.annotation.ElementType;
@@ -91,13 +92,31 @@
}
/**
- * Marks that an element - and all its attributes and children - are
- * trusted content.
+ * Marks that an element and all its attributes are trusted content.
+ * This status is preserved across {...@link Node#cloneNode} calls. Be
+ * extremely careful when using this, especially with {...@code
includingChildren}
+ * set to {...@code true}, as untrusted content that gets inserted (e.g, via
+ * os:RenderAll in templating) would become trusted.
+ *
+ * @param element the trusted element
+ * @param includingChildren if true, children of this element will are also
+ * trusted. Never set this to true on an element that will ever have
+ * untrusted children inserted (e.g., if it contains or may contain
os:Render).
*/
- public static void bypassSanitization(Element element) {
- element.setUserData(BYPASS_SANITIZATION_KEY, true, null);
+ public static void bypassSanitization(Element element, boolean
includingChildren) {
+ element.setUserData(BYPASS_SANITIZATION_KEY,
+ includingChildren ? Bypass.ALL : Bypass.ONLY_SELF, copyOnClone);
}
+ private static enum Bypass { ALL, ONLY_SELF, NONE };
+ private static UserDataHandler copyOnClone = new UserDataHandler() {
+ public void handle(short operation, String key, Object data, Node src,
Node dst) {
+ if (operation == NODE_CLONED) {
+ dst.setUserData(key, data, copyOnClone);
+ }
+ }
+ };
+
private final Set<String> allowedTags;
private final Set<String> allowedAttributes;
private final CajaCssSanitizer cssSanitizer;
@@ -249,8 +268,13 @@
case Node.ELEMENT_NODE:
case Node.DOCUMENT_NODE:
Element element = (Element) node;
- if (canBypassSanitization(element)) {
+ Bypass bypass = canBypassSanitization(element);
+ if (bypass == Bypass.ALL) {
return;
+ } else if (bypass == Bypass.ONLY_SELF) {
+ for (Node child : toList(node.getChildNodes())) {
+ sanitize(child);
+ }
} else if (allowedTags.contains(element.getTagName().toLowerCase()))
{
// TODO - Add special case for stylesheet LINK nodes.
// Special case handling for style nodes
@@ -314,8 +338,12 @@
return list;
}
- private static boolean canBypassSanitization(Element element) {
- return (element.getUserData(BYPASS_SANITIZATION_KEY) != null);
+ private static Bypass canBypassSanitization(Element element) {
+ Bypass bypass = (Bypass) element.getUserData(BYPASS_SANITIZATION_KEY);
+ if (bypass == null) {
+ bypass = Bypass.NONE;
+ }
+ return bypass;
}
/** Convert a NamedNodeMap to a list for easy and safe operations */
Modified:
incubator/shindig/trunk/java/gadgets/src/test/java/org/apache/shindig/gadgets/render/SanitizedRenderingContentRewriterTest.java
URL:
http://svn.apache.org/viewvc/incubator/shindig/trunk/java/gadgets/src/test/java/org/apache/shindig/gadgets/render/SanitizedRenderingContentRewriterTest.java?rev=758466&r1=758465&r2=758466&view=diff
==============================================================================
---
incubator/shindig/trunk/java/gadgets/src/test/java/org/apache/shindig/gadgets/render/SanitizedRenderingContentRewriterTest.java
(original)
+++
incubator/shindig/trunk/java/gadgets/src/test/java/org/apache/shindig/gadgets/render/SanitizedRenderingContentRewriterTest.java
Wed Mar 25 23:45:04 2009
@@ -226,7 +226,7 @@
assertEquals(sanitized, rewrite(req, response));
}
- @Test
+ @Test
public void validProxiedImageAccepted() throws Exception {
HttpRequest req = new HttpRequest(CONTENT_URI);
req.setRewriteMimeType("image/*");
@@ -236,28 +236,75 @@
assertNull(rewrite(req, response));
}
- @Test
- public void sanitizationBypassAllowed() {
- String markup = "<p foo=\"bar\"><b>Parag</b><!--raph--></p>";
- // Create a rewriter that would strip everything
- ContentRewriter rewriter = createRewriter(set(), set());
-
- MutableContent mc = new MutableContent(parser, markup);
- Document document = mc.getDocument();
- // Force the content to get re-serialized
- MutableContent.notifyEdit(document);
- String fullMarkup = mc.getContent();
-
- Element paragraphTag = (Element)
document.getElementsByTagName("p").item(0);
- // Mark the paragraph tag element as trusted
- SanitizedRenderingContentRewriter.bypassSanitization(paragraphTag);
- rewriter.rewrite(gadget, mc);
-
- // The document should be unchanged
- assertEquals(fullMarkup, mc.getContent());
- }
+ @Test
+ public void sanitizationBypassAllowed() {
+ String markup = "<p foo=\"bar\"><b>Parag</b><!--raph--></p>";
+ // Create a rewriter that would strip everything
+ ContentRewriter rewriter = createRewriter(set(), set());
+
+ MutableContent mc = new MutableContent(parser, markup);
+ Document document = mc.getDocument();
+ // Force the content to get re-serialized
+ MutableContent.notifyEdit(document);
+ String fullMarkup = mc.getContent();
+
+ Element paragraphTag = (Element)
document.getElementsByTagName("p").item(0);
+ // Mark the paragraph tag element as trusted
+ SanitizedRenderingContentRewriter.bypassSanitization(paragraphTag, true);
+ rewriter.rewrite(gadget, mc);
+
+ // The document should be unchanged
+ assertEquals(fullMarkup, mc.getContent());
+ }
+
+ @Test
+ public void sanitizationBypassOnlySelf() {
+ String markup = "<p foo=\"bar\"><b>Parag</b><!--raph--></p>";
+ // Create a rewriter that would strip everything
+ ContentRewriter rewriter = createRewriter(set(), set());
+
+ MutableContent mc = new MutableContent(parser, markup);
+ Document document = mc.getDocument();
+
+ Element paragraphTag = (Element)
document.getElementsByTagName("p").item(0);
+ // Mark the paragraph tag element as trusted
+ SanitizedRenderingContentRewriter.bypassSanitization(paragraphTag, false);
+ rewriter.rewrite(gadget, mc);
+
+ // The document should be unchanged
+ String content = mc.getContent();
+ Matcher matcher = BODY_REGEX.matcher(content);
+ matcher.matches();
+ assertEquals("<p foo=\"bar\"></p>", matcher.group(1));
+ }
+
+ @Test
+ public void sanitizationBypassPreservedAcrossClone() {
+ String markup = "<p foo=\"bar\"><b>Parag</b><!--raph--></p>";
+ // Create a rewriter that would strip everything
+ ContentRewriter rewriter = createRewriter(set(), set());
+
+ MutableContent mc = new MutableContent(parser, markup);
+ Document document = mc.getDocument();
+
+ Element paragraphTag = (Element)
document.getElementsByTagName("p").item(0);
+ // Mark the paragraph tag element as trusted
+ SanitizedRenderingContentRewriter.bypassSanitization(paragraphTag, false);
+
+ // Now, clone the paragraph tag and replace the paragraph tag
+ Element cloned = (Element) paragraphTag.cloneNode(true);
+ paragraphTag.getParentNode().replaceChild(cloned, paragraphTag);
- @Test
+ rewriter.rewrite(gadget, mc);
+
+ // The document should be unchanged
+ String content = mc.getContent();
+ Matcher matcher = BODY_REGEX.matcher(content);
+ matcher.matches();
+ assertEquals("<p foo=\"bar\"></p>", matcher.group(1));
+ }
+
+ @Test
public void restrictHrefAndSrcAttributes() {
String markup =
"<element " +