Return-Path: X-Original-To: apmail-sling-commits-archive@www.apache.org Delivered-To: apmail-sling-commits-archive@www.apache.org Received: from mail.apache.org (hermes.apache.org [140.211.11.3]) by minotaur.apache.org (Postfix) with SMTP id 3E7A0888F for ; Tue, 30 Aug 2011 03:19:02 +0000 (UTC) Received: (qmail 19374 invoked by uid 500); 30 Aug 2011 03:18:58 -0000 Delivered-To: apmail-sling-commits-archive@sling.apache.org Received: (qmail 19313 invoked by uid 500); 30 Aug 2011 03:18:48 -0000 Mailing-List: contact commits-help@sling.apache.org; run by ezmlm Precedence: bulk List-Help: List-Unsubscribe: List-Post: List-Id: Reply-To: dev@sling.apache.org Delivered-To: mailing list commits@sling.apache.org Received: (qmail 19306 invoked by uid 99); 30 Aug 2011 03:18:46 -0000 Received: from athena.apache.org (HELO athena.apache.org) (140.211.11.136) by apache.org (qpsmtpd/0.29) with ESMTP; Tue, 30 Aug 2011 03:18:46 +0000 X-ASF-Spam-Status: No, hits=-2000.0 required=5.0 tests=ALL_TRUSTED X-Spam-Check-By: apache.org Received: from [140.211.11.4] (HELO eris.apache.org) (140.211.11.4) by apache.org (qpsmtpd/0.29) with ESMTP; Tue, 30 Aug 2011 03:18:41 +0000 Received: from eris.apache.org (localhost [127.0.0.1]) by eris.apache.org (Postfix) with ESMTP id 343702388A40; Tue, 30 Aug 2011 03:18:21 +0000 (UTC) Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit Subject: svn commit: r1163078 - in /sling/trunk/samples/urlfilter: ./ src/ src/main/ src/main/java/ src/main/java/org/ src/main/java/org/apache/ src/main/java/org/apache/sling/ src/main/java/org/apache/sling/samples/ src/main/java/org/apache/sling/samples/urlfi... Date: Tue, 30 Aug 2011 03:18:21 -0000 To: commits@sling.apache.org From: justin@apache.org X-Mailer: svnmailer-1.0.8 Message-Id: <20110830031821.343702388A40@eris.apache.org> Author: justin Date: Tue Aug 30 03:18:20 2011 New Revision: 1163078 URL: http://svn.apache.org/viewvc?rev=1163078&view=rev Log: uploading sample url filter implementation Added: sling/trunk/samples/urlfilter/ sling/trunk/samples/urlfilter/pom.xml sling/trunk/samples/urlfilter/src/ sling/trunk/samples/urlfilter/src/main/ sling/trunk/samples/urlfilter/src/main/java/ sling/trunk/samples/urlfilter/src/main/java/org/ sling/trunk/samples/urlfilter/src/main/java/org/apache/ sling/trunk/samples/urlfilter/src/main/java/org/apache/sling/ sling/trunk/samples/urlfilter/src/main/java/org/apache/sling/samples/ sling/trunk/samples/urlfilter/src/main/java/org/apache/sling/samples/urlfilter/ sling/trunk/samples/urlfilter/src/main/java/org/apache/sling/samples/urlfilter/impl/ sling/trunk/samples/urlfilter/src/main/java/org/apache/sling/samples/urlfilter/impl/UrlFilter.java sling/trunk/samples/urlfilter/src/test/ sling/trunk/samples/urlfilter/src/test/java/ sling/trunk/samples/urlfilter/src/test/java/org/ sling/trunk/samples/urlfilter/src/test/java/org/apache/ sling/trunk/samples/urlfilter/src/test/java/org/apache/sling/ sling/trunk/samples/urlfilter/src/test/java/org/apache/sling/samples/ sling/trunk/samples/urlfilter/src/test/java/org/apache/sling/samples/urlfilter/ sling/trunk/samples/urlfilter/src/test/java/org/apache/sling/samples/urlfilter/impl/ sling/trunk/samples/urlfilter/src/test/java/org/apache/sling/samples/urlfilter/impl/UrlFilterTest.java Added: sling/trunk/samples/urlfilter/pom.xml URL: http://svn.apache.org/viewvc/sling/trunk/samples/urlfilter/pom.xml?rev=1163078&view=auto ============================================================================== --- sling/trunk/samples/urlfilter/pom.xml (added) +++ sling/trunk/samples/urlfilter/pom.xml Tue Aug 30 03:18:20 2011 @@ -0,0 +1,109 @@ + + + + 4.0.0 + + org.apache.sling + sling + 11 + ../../parent/pom.xml + + org.apache.sling.samples + org.apache.sling.samples.urlfilter + bundle + 0.0.1-SNAPSHOT + org.apache.sling.samples.urlfilter + org.apache.sling.samples - org.apache.sling.samples.urlfilter + + + + org.apache.felix + maven-scr-plugin + + + generate-scr-descriptor + + scr + + + + + + org.apache.felix + maven-bundle-plugin + true + + + + + + javax.servlet + servlet-api + provided + + + org.osgi + org.osgi.compendium + provided + + + org.osgi + org.osgi.core + provided + + + org.apache.sling + org.apache.sling.api + 2.2.0 + provided + + + org.slf4j + slf4j-api + provided + + + org.apache.felix + org.apache.felix.scr.annotations + provided + + + junit + junit + test + + + commons-lang + commons-lang + 2.4 + provided + + + org.jmock + jmock-junit4 + + + org.slf4j + slf4j-simple + test + + + Added: sling/trunk/samples/urlfilter/src/main/java/org/apache/sling/samples/urlfilter/impl/UrlFilter.java URL: http://svn.apache.org/viewvc/sling/trunk/samples/urlfilter/src/main/java/org/apache/sling/samples/urlfilter/impl/UrlFilter.java?rev=1163078&view=auto ============================================================================== --- sling/trunk/samples/urlfilter/src/main/java/org/apache/sling/samples/urlfilter/impl/UrlFilter.java (added) +++ sling/trunk/samples/urlfilter/src/main/java/org/apache/sling/samples/urlfilter/impl/UrlFilter.java Tue Aug 30 03:18:20 2011 @@ -0,0 +1,202 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +package org.apache.sling.samples.urlfilter.impl; + +import java.io.IOException; +import java.util.Arrays; +import java.util.Collection; +import java.util.Collections; +import java.util.regex.Pattern; + +import javax.servlet.Filter; +import javax.servlet.FilterChain; +import javax.servlet.FilterConfig; +import javax.servlet.ServletException; +import javax.servlet.ServletRequest; +import javax.servlet.ServletResponse; + +import org.apache.commons.lang.ArrayUtils; +import org.apache.felix.scr.annotations.sling.SlingFilter; +import org.apache.felix.scr.annotations.sling.SlingFilterScope; +import org.apache.sling.api.SlingHttpServletRequest; +import org.apache.sling.api.SlingHttpServletResponse; +import org.apache.sling.api.request.RequestPathInfo; +import org.apache.sling.api.resource.Resource; +import org.apache.sling.api.resource.ResourceResolver; +import org.apache.sling.api.resource.ValueMap; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +/** + * Illustration of a technique for url filtering on suffixes, selectors, and/or + * extensions + */ +@SlingFilter(scope = SlingFilterScope.REQUEST, order = Integer.MIN_VALUE) +public class UrlFilter implements Filter { + + static final String PN_ALLOWED_EXTENSION_PATTERN = "allowedExtensionPattern"; + + static final String PN_ALLOWED_EXTENSIONS = "allowedExtensions"; + + static final String PN_ALLOWED_SELECTOR_PATTERN = "allowedSelectorPattern"; + + static final String PN_ALLOWED_SELECTORS = "allowedSelectors"; + + static final String PN_ALLOWED_SUFFIX_PATTERN = "allowedSuffixPattern"; + + static final String PN_ALLOWED_SUFFIXES = "allowedSuffixes"; + + static final Collection PROPERTY_NAMES = Arrays.asList(PN_ALLOWED_SUFFIXES, PN_ALLOWED_EXTENSIONS, + PN_ALLOWED_SELECTORS, PN_ALLOWED_SUFFIX_PATTERN, PN_ALLOWED_SELECTOR_PATTERN, PN_ALLOWED_EXTENSION_PATTERN); + + private Logger logger = LoggerFactory.getLogger(this.getClass()); + + public void destroy() { + // nothing to do + } + + public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, + ServletException { + if (request instanceof SlingHttpServletRequest && response instanceof SlingHttpServletResponse) { + SlingHttpServletRequest slingRequest = (SlingHttpServletRequest) request; + SlingHttpServletResponse slingResponse = (SlingHttpServletResponse) response; + + RequestPathInfo pathInfo = slingRequest.getRequestPathInfo(); + + Resource definitionResource = findUrlFilterDefinitionResource(slingRequest.getResource(), + slingRequest.getResourceResolver()); + + if (definitionResource != null) { + logger.debug("found url filter definition resource at {}", definitionResource.getPath()); + ValueMap properties = definitionResource.adaptTo(ValueMap.class); + if (properties != null) { + if (checkSelector(pathInfo, properties) && checkSuffix(pathInfo, properties) + && checkExtension(pathInfo, properties)) { + logger.debug("url filter definition resource at {} passed for request {}.", + definitionResource.getPath(), slingRequest.getRequestPathInfo()); + } else { + logger.info("url filter definition resource at {} FAILED for request {}.", + definitionResource.getPath(), slingRequest.getRequestPathInfo()); + slingResponse.sendError(403); + return; + } + } + } + + } + + chain.doFilter(request, response); + + } + + public void init(FilterConfig filterConfig) throws ServletException { + // nothing to do + } + + boolean checkExtension(RequestPathInfo pathInfo, ValueMap properties) { + return check(pathInfo.getExtension(), PN_ALLOWED_EXTENSIONS, PN_ALLOWED_EXTENSION_PATTERN, properties); + } + + boolean checkSelector(RequestPathInfo pathInfo, ValueMap properties) { + return check(pathInfo.getSelectorString(), PN_ALLOWED_SELECTORS, PN_ALLOWED_SELECTOR_PATTERN, properties); + } + + boolean check(String value, String allowedArrayPropertyName, String allowedPatternPropertyName, ValueMap properties) { + if (value == null) { + // no value is always allowed + return true; + } + String[] allowedValues = properties.get(allowedArrayPropertyName, String[].class); + if (allowedValues != null) { + if (allowedValues.length == 0) { + logger.debug("{} was empty, therefore not allowing any value.", allowedArrayPropertyName); + return false; + } else if (!ArrayUtils.contains(allowedValues, value)) { + logger.debug("{} did not contain our string {}. checking the pattern.", allowedArrayPropertyName, value); + String allowedPattern = properties.get(allowedPatternPropertyName, String.class); + if (allowedPattern == null || !Pattern.matches(allowedPattern, value)) { + logger.debug("allowedPattern ({}) did not match our string {}", allowedPattern, value); + return false; + } else { + logger.debug("allowedPattern ({}) did match our string {}", allowedPattern, value); + return true; + } + } else { + return true; + } + } else { + String allowedPattern = properties.get(allowedPatternPropertyName, String.class); + if (allowedPattern != null && !Pattern.matches(allowedPattern, value)) { + logger.debug("allowedPattern ({}) did not match our string {}", allowedPattern, value); + return false; + } else { + return true; + } + } + } + + boolean checkSuffix(RequestPathInfo pathInfo, ValueMap properties) { + return check(pathInfo.getSuffix(), PN_ALLOWED_SUFFIXES, PN_ALLOWED_SUFFIX_PATTERN, properties); + } + + Resource findUrlFilterDefinitionResource(Resource resource, ResourceResolver resolver) { + if (resource == null) { + return null; + } + + Resource contentResource = resource.getChild("jcr:content"); + if (contentResource != null) { + resource = contentResource; + } + + String resourceType = resource.getResourceType(); + + Resource definitionResource = findUrlFilterDefinitionResource(resourceType, resolver); + if (definitionResource == null) { + return findUrlFilterDefinitionResource(resource.getResourceSuperType(), resolver); + } else { + return definitionResource; + } + } + + private Resource findUrlFilterDefinitionResource(String resourceType, ResourceResolver resolver) { + if (resourceType == null) { + return null; + } + Resource typeResource = resolver.getResource(resourceType); + if (typeResource == null) { + return null; + } + + ValueMap properties = typeResource.adaptTo(ValueMap.class); + if (properties == null) { + return null; + } + + // Collections.disjoint returns true if the collections + // have nothing in common, so when it is false, use the current resource + if (!Collections.disjoint(properties.keySet(), PROPERTY_NAMES)) { + return typeResource; + } else { + // otherwise, look at the resource type resource's super type + return findUrlFilterDefinitionResource(typeResource.getResourceSuperType(), resolver); + } + + } +} Added: sling/trunk/samples/urlfilter/src/test/java/org/apache/sling/samples/urlfilter/impl/UrlFilterTest.java URL: http://svn.apache.org/viewvc/sling/trunk/samples/urlfilter/src/test/java/org/apache/sling/samples/urlfilter/impl/UrlFilterTest.java?rev=1163078&view=auto ============================================================================== --- sling/trunk/samples/urlfilter/src/test/java/org/apache/sling/samples/urlfilter/impl/UrlFilterTest.java (added) +++ sling/trunk/samples/urlfilter/src/test/java/org/apache/sling/samples/urlfilter/impl/UrlFilterTest.java Tue Aug 30 03:18:20 2011 @@ -0,0 +1,110 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with this + * work for additional information regarding copyright ownership. The ASF + * licenses this file to You under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations under + * the License. + */ +package org.apache.sling.samples.urlfilter.impl; + +import static org.junit.Assert.*; + +import java.util.HashMap; + +import org.apache.sling.api.request.RequestPathInfo; +import org.apache.sling.api.resource.ValueMap; +import org.apache.sling.api.wrappers.ValueMapDecorator; +import org.jmock.Expectations; +import org.jmock.Mockery; +import org.jmock.integration.junit4.JMock; +import org.jmock.integration.junit4.JUnit4Mockery; +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; + +@RunWith(JMock.class) +public class UrlFilterTest { + + private Mockery context = new JUnit4Mockery(); + private ValueMap properties; + + @Before + public void setup() { + properties = new ValueMapDecorator(new HashMap()); + } + + @Test + public void null_selector() { + UrlFilter filter = new UrlFilter(); + + final RequestPathInfo testInfo = context.mock(RequestPathInfo.class); + this.context.checking(new Expectations() { + { + allowing(testInfo).getSelectorString(); + will(returnValue(null)); + } + }); + + assertTrue(filter.checkSelector(testInfo, null)); + } + + @Test + public void non_null_selector() { + UrlFilter filter = new UrlFilter(); + + final RequestPathInfo testInfo = context.mock(RequestPathInfo.class); + this.context.checking(new Expectations() { + { + allowing(testInfo).getSelectorString(); + will(returnValue("sample")); + } + }); + + // null allowedSelectors = ok + assertTrue(filter.checkSelector(testInfo, properties)); + + // empty array allowedSelectors = fail + properties.put(UrlFilter.PN_ALLOWED_SELECTORS, (Object) new String[0]); + assertFalse(filter.checkSelector(testInfo, properties)); + + // selector string in array = ok + properties.put(UrlFilter.PN_ALLOWED_SELECTORS, (Object) new String[] { "sample", "sample2" }); + assertTrue(filter.checkSelector(testInfo, properties)); + + // selector string not in array = fail + properties.put(UrlFilter.PN_ALLOWED_SELECTORS, (Object) new String[] { "other" }); + assertFalse(filter.checkSelector(testInfo, properties)); + + properties.clear(); + + // matches regex + properties.put(UrlFilter.PN_ALLOWED_SELECTOR_PATTERN, "^s[a-z]m.*$"); + assertTrue(filter.checkSelector(testInfo, properties)); + + // doesn't match regex + properties.put(UrlFilter.PN_ALLOWED_SELECTOR_PATTERN, "^s[1-2]m$"); + assertFalse(filter.checkSelector(testInfo, properties)); + + properties.clear(); + + // matches array or regex = ok + properties.put(UrlFilter.PN_ALLOWED_SELECTORS, (Object) new String[] { "other" }); + properties.put(UrlFilter.PN_ALLOWED_SELECTOR_PATTERN, "^s[a-z]m.*$"); + assertTrue(filter.checkSelector(testInfo, properties)); + + properties.put(UrlFilter.PN_ALLOWED_SELECTORS, (Object) new String[] { "sample" }); + properties.put(UrlFilter.PN_ALLOWED_SELECTOR_PATTERN, "^s[a-z]m$"); + assertTrue(filter.checkSelector(testInfo, properties)); + + + } +}