You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@sling.apache.org by ro...@apache.org on 2017/11/07 10:13:43 UTC

[sling-org-apache-sling-security] 13/15: SLING-4883 - Extend content disposition filter protection to jcr:data

This is an automated email from the ASF dual-hosted git repository.

rombert pushed a commit to annotated tag org.apache.sling.security-1.0.12
in repository https://gitbox.apache.org/repos/asf/sling-org-apache-sling-security.git

commit ffbe306a1a48ced6908346f791c37cc5efa72ebc
Author: Antonio Sanso <as...@apache.org>
AuthorDate: Wed Jul 29 10:09:42 2015 +0000

    SLING-4883 - Extend content disposition filter protection to jcr:data
    
    git-svn-id: https://svn.apache.org/repos/asf/sling/trunk/contrib/extensions/security@1693233 13f79535-47bb-0310-9956-ffa450edef68
---
 .../security/impl/ContentDispositionFilter.java    |  67 +++++++----
 .../impl/ContentDispositionFilterTest.java         | 123 ++++++++++++++++++++-
 2 files changed, 166 insertions(+), 24 deletions(-)

diff --git a/src/main/java/org/apache/sling/security/impl/ContentDispositionFilter.java b/src/main/java/org/apache/sling/security/impl/ContentDispositionFilter.java
index 9eccb06..985d263 100644
--- a/src/main/java/org/apache/sling/security/impl/ContentDispositionFilter.java
+++ b/src/main/java/org/apache/sling/security/impl/ContentDispositionFilter.java
@@ -67,6 +67,13 @@ public class ContentDispositionFilter implements Filter {
                     "Invalid entries are logged and ignored."
                     , unbounded = PropertyUnbounded.ARRAY, value = { "" })
     private static final String PROP_CONTENT_DISPOSTION_PATHS = "sling.content.disposition.paths";
+    
+    private static final boolean DEFAULT_ENABLE_CONTENT_DISPOSTION_ALL_PATHS = false;
+    @Property(boolValue = DEFAULT_ENABLE_CONTENT_DISPOSTION_ALL_PATHS ,
+              label = "Enable Content Disposition for all paths",
+              description ="This flag controls whether to enable" +
+                      " Content Disposition for all paths.")
+    private static final String PROP_ENABLE_CONTENT_DISPOSTION_ALL_PATHS = "sling.content.disposition.all.paths";
    
     /**
      * Set of paths
@@ -80,6 +87,8 @@ public class ContentDispositionFilter implements Filter {
 
     private Map<String, Set<String>> contentTypesMapping;
     
+    private boolean enableContentDispositionAllPaths;
+    
     @Activate
     private void activate(final ComponentContext ctx) {
         final Dictionary props = ctx.getProperties();
@@ -131,8 +140,10 @@ public class ContentDispositionFilter implements Filter {
         contentDispositionPathsPfx = pfxs.toArray(new String[pfxs.size()]);
         contentTypesMapping = contentTypesMap.isEmpty()?Collections.<String, Set<String>>emptyMap(): contentTypesMap;
         
-        logger.info("Initialized. content disposition paths: {}, content disposition paths-pfx {}", new Object[]{
-                contentDispositionPaths, contentDispositionPathsPfx}
+        enableContentDispositionAllPaths =  PropertiesUtil.toBoolean(props.get(PROP_ENABLE_CONTENT_DISPOSTION_ALL_PATHS),DEFAULT_ENABLE_CONTENT_DISPOSTION_ALL_PATHS);
+        
+        logger.info("Initialized. content disposition paths: {}, content disposition paths-pfx {}. Enable Content Disposition for all paths is set to {}", new Object[]{
+                contentDispositionPaths, contentDispositionPathsPfx, enableContentDispositionAllPaths}
         );
     }
     
@@ -203,33 +214,40 @@ public class ContentDispositionFilter implements Filter {
             }
             request.setAttribute(ATTRIBUTE_NAME, type);
             Resource resource = request.getResource();
-            String resourcePath = resource.getPath();
             
-            if (contentDispositionPaths.contains(resourcePath)) {
+            if (enableContentDispositionAllPaths) {
+                setContentDisposition(resource);
+            } else {
+                String resourcePath = resource.getPath();
 
-                if (contentTypesMapping.containsKey(resourcePath)) {
-                    Set <String> exceptions = contentTypesMapping.get(resourcePath);
-                    if (!exceptions.contains(type)) {
-                        setContentDisposition(resource);
-                    }
-                } else {
-                    setContentDisposition(resource);
-                }
-            }
-            
-            for (String path : contentDispositionPathsPfx) {
-                if (resourcePath.startsWith(path)) {
-                    if (contentTypesMapping.containsKey(path)) {
-                        Set <String> exceptions = contentTypesMapping.get(path);
+                boolean contentDispositionAdded = false;
+                if (contentDispositionPaths.contains(resourcePath)) {
+
+                    if (contentTypesMapping.containsKey(resourcePath)) {
+                        Set <String> exceptions = contentTypesMapping.get(resourcePath);
                         if (!exceptions.contains(type)) {
-                            setContentDisposition(resource);
-                            break;
+                            contentDispositionAdded = setContentDisposition(resource);
                         }
                     } else {
-                        setContentDisposition(resource);
-                        break;
+                        contentDispositionAdded = setContentDisposition(resource);
                     }
+                }            
+                if (!contentDispositionAdded) {
+                    for (String path : contentDispositionPathsPfx) {
+                        if (resourcePath.startsWith(path)) {
+                            if (contentTypesMapping.containsKey(path)) {
+                                Set <String> exceptions = contentTypesMapping.get(path);
+                                if (!exceptions.contains(type)) {
+                                    setContentDisposition(resource);
+                                    break;
+                                }
+                            } else {
+                                setContentDisposition(resource);
+                                break;
+                            }
 
+                        }
+                    }
                 }
             }
             super.setContentType(type);
@@ -237,10 +255,13 @@ public class ContentDispositionFilter implements Filter {
         
       //---------- PRIVATE METHODS ---------
         
-        private void setContentDisposition(Resource resource) {
+        private boolean setContentDisposition(Resource resource) {
+            boolean contentDispositionAdded = false;
             if (!this.containsHeader(CONTENT_DISPOSTION) && this.isJcrData(resource)) {
                 this.addHeader(CONTENT_DISPOSTION, CONTENT_DISPOSTION_ATTACHMENT);
+                contentDispositionAdded = true;
             }
+            return contentDispositionAdded;
         }
         
         private boolean isJcrData(Resource resource){
diff --git a/src/test/java/org/apache/sling/security/impl/ContentDispositionFilterTest.java b/src/test/java/org/apache/sling/security/impl/ContentDispositionFilterTest.java
index abc2c4f..aaf9ddb 100644
--- a/src/test/java/org/apache/sling/security/impl/ContentDispositionFilterTest.java
+++ b/src/test/java/org/apache/sling/security/impl/ContentDispositionFilterTest.java
@@ -869,7 +869,8 @@ public class ContentDispositionFilterTest {
         rewriterResponse.setContentType("text/html");
         rewriterResponse.setContentType("text/html");
         Assert.assertEquals(1, counter.intValue());
-    } 
+    }
+    
     /**
      * Test repeated setContentType calls don't add multiple headers, case 2 changing mime type
      * @throws Throwable
@@ -933,6 +934,126 @@ public class ContentDispositionFilterTest {
         Assert.assertEquals(1, counter.intValue());
     }
     
+
+    @Test
+    public void test_doFilter17() throws Throwable{       
+        final SlingHttpServletRequest request = context.mock(SlingHttpServletRequest.class);
+        final SlingHttpServletResponse response = context.mock(SlingHttpServletResponse.class);
+        final Resource resource = context.mock(Resource.class, "resource" );   
+        final ValueMap properties = context.mock(ValueMap.class);
+        contentDispositionFilter = new ContentDispositionFilter();
+        
+        final ComponentContext ctx = context.mock(ComponentContext.class);
+        final Dictionary props = new Hashtable<String, String[]>();
+        props.put("sling.content.disposition.paths", new String []{"/content/usergenerated"});
+        props.put("sling.content.disposition.all.paths", false);
+        
+        context.checking(new Expectations() {
+            {
+                allowing(ctx).getProperties();
+                will(returnValue(props));
+                
+            }
+        });    
+        PrivateAccessor.invoke(contentDispositionFilter,"activate",  new Class[]{ComponentContext.class},new Object[]{ctx});
+        final AtomicInteger counter =  new AtomicInteger();        
+        final ContentDispositionFilter.RewriterResponse rewriterResponse = contentDispositionFilter. new RewriterResponse(request, response) {          
+            public void addHeader(String name, String value) {
+                counter.incrementAndGet();
+            }
+        };
+
+        
+        context.checking(new Expectations() {
+            {
+                exactly(1).of(response).containsHeader("Content-Disposition");
+                will(returnValue(false));
+                exactly(1).of(response).containsHeader("Content-Disposition");
+                will(returnValue(true));
+                exactly(1).of(request).getAttribute(RewriterResponse.ATTRIBUTE_NAME);
+                will(returnValue(null));
+                exactly(1).of(request).getAttribute(RewriterResponse.ATTRIBUTE_NAME);
+                will(returnValue("text/html"));
+                allowing(request).setAttribute(RewriterResponse.ATTRIBUTE_NAME, "text/xml");
+                allowing(request).setAttribute(RewriterResponse.ATTRIBUTE_NAME, "text/html");
+                allowing(request).getResource();
+                will(returnValue(resource));
+                allowing(resource).getPath();
+                will(returnValue("/content/other"));
+                allowing(resource).adaptTo(ValueMap.class);
+                will(returnValue(properties));
+                allowing(properties).containsKey(PROP_JCR_DATA);
+                will(returnValue(true));
+                allowing(response).setContentType("text/html");
+                allowing(response).setContentType("text/xml");
+                //CONTENT DISPOSITION IS NOT SET
+                never(response).addHeader("Content-Disposition", "attachment");
+            }
+        });       
+        rewriterResponse.setContentType("text/html");
+        Assert.assertEquals(0, counter.intValue());
+    }
+    
+ 
+    @Test
+    public void test_doFilter18() throws Throwable{       
+        final SlingHttpServletRequest request = context.mock(SlingHttpServletRequest.class);
+        final SlingHttpServletResponse response = context.mock(SlingHttpServletResponse.class);
+        final Resource resource = context.mock(Resource.class, "resource" );   
+        final ValueMap properties = context.mock(ValueMap.class);
+        contentDispositionFilter = new ContentDispositionFilter();
+        
+        final ComponentContext ctx = context.mock(ComponentContext.class);
+        final Dictionary props = new Hashtable<String, String[]>();
+        props.put("sling.content.disposition.paths", new String []{"/content/usergenerated"});
+        props.put("sling.content.disposition.all.paths", true);
+        
+        context.checking(new Expectations() {
+            {
+                allowing(ctx).getProperties();
+                will(returnValue(props));
+                
+            }
+        });    
+        PrivateAccessor.invoke(contentDispositionFilter,"activate",  new Class[]{ComponentContext.class},new Object[]{ctx});
+        final AtomicInteger counter =  new AtomicInteger();        
+        final ContentDispositionFilter.RewriterResponse rewriterResponse = contentDispositionFilter. new RewriterResponse(request, response) {          
+            public void addHeader(String name, String value) {
+                counter.incrementAndGet();
+            }
+        };
+
+        
+        context.checking(new Expectations() {
+            {
+                exactly(1).of(response).containsHeader("Content-Disposition");
+                will(returnValue(false));
+                exactly(1).of(response).containsHeader("Content-Disposition");
+                will(returnValue(true));
+                exactly(1).of(request).getAttribute(RewriterResponse.ATTRIBUTE_NAME);
+                will(returnValue(null));
+                exactly(1).of(request).getAttribute(RewriterResponse.ATTRIBUTE_NAME);
+                will(returnValue("text/html"));
+                allowing(request).setAttribute(RewriterResponse.ATTRIBUTE_NAME, "text/xml");
+                allowing(request).setAttribute(RewriterResponse.ATTRIBUTE_NAME, "text/html");
+                allowing(request).getResource();
+                will(returnValue(resource));
+                allowing(resource).getPath();
+                will(returnValue("/content/other"));
+                allowing(resource).adaptTo(ValueMap.class);
+                will(returnValue(properties));
+                allowing(properties).containsKey(PROP_JCR_DATA);
+                will(returnValue(true));
+                allowing(response).setContentType("text/html");
+                allowing(response).setContentType("text/xml");
+                //CONTENT DISPOSITION IS SET
+                exactly(1).of(response).addHeader("Content-Disposition", "attachment");
+            }
+        });       
+        rewriterResponse.setContentType("text/html");
+        Assert.assertEquals(1, counter.intValue());
+    }
+    
     @Test
     public void test_isJcrData1() throws Throwable {
         contentDispositionFilter = new ContentDispositionFilter();

-- 
To stop receiving notification emails like this one, please contact
"commits@sling.apache.org" <co...@sling.apache.org>.