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 " +


Reply via email to