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.0 in repository https://gitbox.apache.org/repos/asf/sling-org-apache-sling-security.git
commit ac5acb361b4b53b2140436695459a4a6ef11f704 Author: Carsten Ziegeler <[email protected]> AuthorDate: Fri Jul 15 06:07:54 2011 +0000 SLING-2141 - Add a way to check the referrer for modification requests git-svn-id: https://svn.apache.org/repos/asf/sling/trunk/contrib/extensions/security@1146968 13f79535-47bb-0310-9956-ffa450edef68 --- pom.xml | 14 ++++ .../apache/sling/security/impl/ReferrerFilter.java | 55 ++++++++++------ .../sling/security/impl/ReferrerFilterTest.java | 74 ++++++++++++++++++++++ 3 files changed, 124 insertions(+), 19 deletions(-) diff --git a/pom.xml b/pom.xml index 84adade..2c9ef01 100644 --- a/pom.xml +++ b/pom.xml @@ -94,5 +94,19 @@ <groupId>org.slf4j</groupId> <artifactId>slf4j-api</artifactId> </dependency> + <dependency> + <groupId>junit</groupId> + <artifactId>junit</artifactId> + </dependency> + <dependency> + <groupId>org.slf4j</groupId> + <artifactId>slf4j-simple</artifactId> + </dependency> + <dependency> + <groupId>org.mockito</groupId> + <artifactId>mockito-all</artifactId> + <version>1.8.2</version> + <scope>test</scope> + </dependency> </dependencies> </project> diff --git a/src/main/java/org/apache/sling/security/impl/ReferrerFilter.java b/src/main/java/org/apache/sling/security/impl/ReferrerFilter.java index 9c0cae2..ed3dec5 100644 --- a/src/main/java/org/apache/sling/security/impl/ReferrerFilter.java +++ b/src/main/java/org/apache/sling/security/impl/ReferrerFilter.java @@ -1,19 +1,22 @@ /* - * Copyright 1997-2011 Day Management AG - * Barfuesserplatz 6, 4001 Basel, Switzerland - * All Rights Reserved. + * 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 * - * This software is the confidential and proprietary information of - * Day Management AG, ("Confidential Information"). You shall not - * disclose such Confidential Information and shall use it only in - * accordance with the terms of the license agreement you entered into - * with Day. + * 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.security.impl; import java.io.IOException; -import java.net.URI; -import java.net.URISyntaxException; import javax.servlet.Filter; import javax.servlet.FilterChain; @@ -38,6 +41,9 @@ import org.slf4j.LoggerFactory; label="%referrer.name") public class ReferrerFilter implements Filter { + /** Logger. */ + private final Logger logger = LoggerFactory.getLogger(this.getClass()); + private static final boolean DEFAULT_ALLOW_EMPTY = true; @Property(boolValue=DEFAULT_ALLOW_EMPTY) @@ -65,9 +71,6 @@ public class ReferrerFilter implements Filter { } } - /** Logger. */ - private final Logger logger = LoggerFactory.getLogger(this.getClass()); - private boolean isModification(final HttpServletRequest req) { final String method = req.getMethod(); if ("POST".equals(method)) { @@ -100,7 +103,23 @@ public class ReferrerFilter implements Filter { chain.doFilter(req, res); } - private boolean isValidRequest(final HttpServletRequest request) { + String getHost(final String referrer) { + final int startPos = referrer.indexOf("://") + 3; + if ( startPos == 2 ) { + // we consider this illegal + return null; + } + final int endPos = referrer.indexOf('/', startPos); + final String hostPart = (endPos == -1 ? referrer.substring(startPos) : referrer.substring(startPos, endPos)); + final int hostNameStart = hostPart.indexOf('@') + 1; + final int hostNameEnd = hostPart.lastIndexOf(':'); + if (hostNameEnd < hostNameStart ) { + return hostPart.substring(hostNameStart); + } + return hostPart.substring(hostNameStart, hostNameEnd); + } + + boolean isValidRequest(final HttpServletRequest request) { final String referrer = request.getHeader("referer"); // check for missing/empty referrer if ( referrer == null || referrer.trim().length() == 0 ) { @@ -113,16 +132,14 @@ public class ReferrerFilter implements Filter { if ( referrer.indexOf(":/") == - 1 ) { return true; } - final URI uri; - try { - uri = new URI(referrer); - } catch (URISyntaxException e) { + + final String host = getHost(referrer); + if ( host == null ) { // if this is invalid we just return invalid this.logger.info("Rejected illegal referrer header for {} request to {} : {}", new Object[] {request.getMethod(), request.getRequestURI(), referrer}); return false; } - final String host = uri.getHost(); final boolean valid; if ( this.allowHosts == null ) { valid = host.equals(request.getServerName()); diff --git a/src/test/java/org/apache/sling/security/impl/ReferrerFilterTest.java b/src/test/java/org/apache/sling/security/impl/ReferrerFilterTest.java new file mode 100644 index 0000000..f6264c1 --- /dev/null +++ b/src/test/java/org/apache/sling/security/impl/ReferrerFilterTest.java @@ -0,0 +1,74 @@ +/* + * 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.security.impl; + +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.when; + +import java.util.Dictionary; +import java.util.Hashtable; + +import javax.servlet.http.HttpServletRequest; + +import org.junit.Assert; +import org.junit.Before; +import org.junit.Test; +import org.osgi.service.component.ComponentContext; + +public class ReferrerFilterTest { + + protected ReferrerFilter filter; + + @Before public void setup() { + filter = new ReferrerFilter(); + final ComponentContext ctx = mock(ComponentContext.class); + final Dictionary<String, Object> props = new Hashtable<String, Object>(); + when(ctx.getProperties()).thenReturn(props); + filter.activate(ctx); + } + + @Test public void testHostName() { + Assert.assertEquals("somehost", filter.getHost("http://somehost")); + Assert.assertEquals("somehost", filter.getHost("http://somehost/somewhere")); + Assert.assertEquals("somehost", filter.getHost("http://somehost:4242/somewhere")); + Assert.assertEquals("somehost", filter.getHost("http://admin@somehost/somewhere")); + Assert.assertEquals("somehost", filter.getHost("http://admin@somehost:1/somewhere")); + Assert.assertEquals("somehost", filter.getHost("http://admin:admin@somehost/somewhere")); + Assert.assertEquals("somehost", filter.getHost("http://admin:admin@somehost:4343/somewhere")); + Assert.assertEquals(null, filter.getHost("http:/admin:admin@somehost:4343/somewhere")); + } + + private HttpServletRequest getRequest(final String referrer) { + final HttpServletRequest request = mock(HttpServletRequest.class); + when(request.getMethod()).thenReturn("POST"); + when(request.getRequestURI()).thenReturn("http://somehost/somewhere"); + when(request.getHeader("referer")).thenReturn(referrer); + when(request.getServerName()).thenReturn("me"); + return request; + } + + @Test public void testValidRequest() { + Assert.assertEquals(true, filter.isValidRequest(getRequest(null))); + Assert.assertEquals(true, filter.isValidRequest(getRequest("relative"))); + Assert.assertEquals(true, filter.isValidRequest(getRequest("/relative/too"))); + Assert.assertEquals(true, filter.isValidRequest(getRequest("/relative/but/[illegal]"))); + Assert.assertEquals(false, filter.isValidRequest(getRequest("http://somehost"))); + Assert.assertEquals(true, filter.isValidRequest(getRequest("http://me"))); + Assert.assertEquals(false, filter.isValidRequest(getRequest("http://somehost/but/[illegal]"))); + Assert.assertEquals(true, filter.isValidRequest(getRequest("http://me/but/[illegal]"))); + } +} -- To stop receiving notification emails like this one, please contact "[email protected]" <[email protected]>.
