You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@shiro.apache.org by bd...@apache.org on 2020/11/04 15:48:10 UTC

[shiro] branch master updated (a61a1c4 -> 5b1add9)

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

bdemers pushed a change to branch master
in repository https://gitbox.apache.org/repos/asf/shiro.git.


    from a61a1c4  Merge pull request #261 from fpapon/jenkins
     new 16fc47a  Add ShiroUrlHelper and related Spring configuration
     new 042c593  Adds configuration to toggle the normalization of backslashes
     new 5b1add9  Disable jsessionid URL rewriting by default

The 3 revisions listed above as "new" are entirely new to this
repository and will be described in separate emails.  The revisions
listed as "add" were already present in the repository and have only
been added to this reference.


Summary of changes:
 .../samples/spring/config/ApplicationConfig.java   |  4 +-
 .../samples/spring/config/JspViewsConfig.java      |  4 +-
 .../autoconfigure/ShiroWebAutoConfiguration.java   | 10 ++++
 .../ShiroWebMvcAutoConfiguration.java}             | 21 ++++---
 .../src/main/resources/META-INF/spring.factories   |  3 +-
 support/spring/pom.xml                             | 15 +++--
 .../shiro/spring/web/ShiroUrlPathHelper.java}      | 31 ++++------
 .../web/config/AbstractShiroWebConfiguration.java  |  7 ++-
 .../web/config/ShiroRequestMappingConfig.java}     | 18 ++----
 .../spring/web/config/ShiroWebConfiguration.java   |  7 +++
 .../shiro/spring/web/ShiroUrlPathHelperTest.groovy | 46 +++++++++++++++
 .../shiro/web/filter/InvalidRequestFilter.java     | 22 +++++--
 .../web/session/mgt/DefaultWebSessionManager.java  |  2 +-
 .../java/org/apache/shiro/web/util/WebUtils.java   |  4 +-
 .../web/filter/InvalidRequestFilterTest.groovy     | 48 +++++++++++++--
 .../mgt/DefaultWebSessionManagerTest.groovy        |  5 +-
 .../org/apache/shiro/web/util/WebUtilsTest.groovy  | 52 ++++++++++++++++
 .../apache/shiro/web/RestoreSystemProperties.java  | 69 ++++++++++++++++++++++
 18 files changed, 302 insertions(+), 66 deletions(-)
 copy support/{spring/src/test/java/org/apache/shiro/spring/web/testconfig/CacheManagerConfiguration.java => spring-boot/spring-boot-web-starter/src/main/java/org/apache/shiro/spring/config/web/autoconfigure/ShiroWebMvcAutoConfiguration.java} (57%)
 copy support/spring/src/{test/java/org/apache/shiro/spring/web/DummyFilter.java => main/java/org/apache/shiro/spring/web/ShiroUrlPathHelper.java} (59%)
 copy support/spring/src/{test/java/org/apache/shiro/spring/testconfig/EventBusTestConfiguration.java => main/java/org/apache/shiro/spring/web/config/ShiroRequestMappingConfig.java} (68%)
 create mode 100644 support/spring/src/test/groovy/org/apache/shiro/spring/web/ShiroUrlPathHelperTest.groovy
 create mode 100644 web/src/test/java/org/apache/shiro/web/RestoreSystemProperties.java


[shiro] 03/03: Disable jsessionid URL rewriting by default

Posted by bd...@apache.org.
This is an automated email from the ASF dual-hosted git repository.

bdemers pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/shiro.git

commit 5b1add9a4c4ed046b52cf2132ed0f264a22caf1d
Author: Brian Demers <bd...@apache.org>
AuthorDate: Tue Sep 29 17:59:29 2020 -0400

    Disable jsessionid URL rewriting by default
    
    This matches the default of the InvalidRequestFilter
    
    Fixes: SHIRO-795
---
 .../shiro/spring/web/config/AbstractShiroWebConfiguration.java       | 2 +-
 .../org/apache/shiro/web/session/mgt/DefaultWebSessionManager.java   | 2 +-
 .../apache/shiro/web/session/mgt/DefaultWebSessionManagerTest.groovy | 5 ++++-
 3 files changed, 6 insertions(+), 3 deletions(-)

diff --git a/support/spring/src/main/java/org/apache/shiro/spring/web/config/AbstractShiroWebConfiguration.java b/support/spring/src/main/java/org/apache/shiro/spring/web/config/AbstractShiroWebConfiguration.java
index 5ed98d8..fab145f 100644
--- a/support/spring/src/main/java/org/apache/shiro/spring/web/config/AbstractShiroWebConfiguration.java
+++ b/support/spring/src/main/java/org/apache/shiro/spring/web/config/AbstractShiroWebConfiguration.java
@@ -43,7 +43,7 @@ public class AbstractShiroWebConfiguration extends AbstractShiroConfiguration {
     @Value("#{ @environment['shiro.sessionManager.sessionIdCookieEnabled'] ?: true }")
     protected boolean sessionIdCookieEnabled;
 
-    @Value("#{ @environment['shiro.sessionManager.sessionIdUrlRewritingEnabled'] ?: true }")
+    @Value("#{ @environment['shiro.sessionManager.sessionIdUrlRewritingEnabled'] ?: false }")
     protected boolean sessionIdUrlRewritingEnabled;
 
     @Value("#{ @environment['shiro.userNativeSessionManager'] ?: false }")
diff --git a/web/src/main/java/org/apache/shiro/web/session/mgt/DefaultWebSessionManager.java b/web/src/main/java/org/apache/shiro/web/session/mgt/DefaultWebSessionManager.java
index eb7eda1..9aa275a 100644
--- a/web/src/main/java/org/apache/shiro/web/session/mgt/DefaultWebSessionManager.java
+++ b/web/src/main/java/org/apache/shiro/web/session/mgt/DefaultWebSessionManager.java
@@ -58,7 +58,7 @@ public class DefaultWebSessionManager extends DefaultSessionManager implements W
         cookie.setHttpOnly(true); //more secure, protects against XSS attacks
         this.sessionIdCookie = cookie;
         this.sessionIdCookieEnabled = true;
-        this.sessionIdUrlRewritingEnabled = true;
+        this.sessionIdUrlRewritingEnabled = false;
     }
 
     public Cookie getSessionIdCookie() {
diff --git a/web/src/test/groovy/org/apache/shiro/web/session/mgt/DefaultWebSessionManagerTest.groovy b/web/src/test/groovy/org/apache/shiro/web/session/mgt/DefaultWebSessionManagerTest.groovy
index 841569f..35b3120 100644
--- a/web/src/test/groovy/org/apache/shiro/web/session/mgt/DefaultWebSessionManagerTest.groovy
+++ b/web/src/test/groovy/org/apache/shiro/web/session/mgt/DefaultWebSessionManagerTest.groovy
@@ -127,7 +127,7 @@ public class DefaultWebSessionManagerTest {
                 ShiroHttpServletRequest.COOKIE_SESSION_ID_SOURCE);
         request.setAttribute(ShiroHttpServletRequest.REFERENCED_SESSION_ID, id);
         request.setAttribute(ShiroHttpServletRequest.REFERENCED_SESSION_ID_IS_VALID, Boolean.TRUE);
-        request.setAttribute(ShiroHttpServletRequest.SESSION_ID_URL_REWRITING_ENABLED, Boolean.TRUE);
+        request.setAttribute(ShiroHttpServletRequest.SESSION_ID_URL_REWRITING_ENABLED, Boolean.FALSE);
 
         replay(cookie);
         replay(request);
@@ -147,6 +147,7 @@ public class DefaultWebSessionManagerTest {
         Cookie cookie = createMock(Cookie.class);
         mgr.setSessionIdCookie(cookie);
         mgr.setSessionIdCookieEnabled(false);
+        mgr.setSessionIdUrlRewritingEnabled(true)
 
         //we should not have any reads from the cookie fields - if we do, this test case will fail.
 
@@ -182,6 +183,7 @@ public class DefaultWebSessionManagerTest {
         Cookie cookie = createMock(Cookie.class);
         mgr.setSessionIdCookie(cookie);
         mgr.setSessionIdCookieEnabled(false);
+        mgr.setSessionIdUrlRewritingEnabled(true)
 
         //we should not have any reads from the cookie fields - if we do, this test case will fail.
 
@@ -218,6 +220,7 @@ public class DefaultWebSessionManagerTest {
     public void testGetSessionIdFromRequestUriPathSegmentParam() {
 
         mgr.setSessionIdCookieEnabled(false);
+        mgr.setSessionIdUrlRewritingEnabled(true)
 
         HttpServletRequest request = createMock(HttpServletRequest.class);
         HttpServletResponse response = createMock(HttpServletResponse.class);


[shiro] 02/03: Adds configuration to toggle the normalization of backslashes

Posted by bd...@apache.org.
This is an automated email from the ASF dual-hosted git repository.

bdemers pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/shiro.git

commit 042c59356cc6442345a9f935aed3e7603cb4dfad
Author: Brian Demers <bd...@apache.org>
AuthorDate: Thu Sep 3 14:58:45 2020 -0400

    Adds configuration to toggle the normalization of backslashes
    
    This is normally handled by the container
    Update the InvalidRequestFilter to use WebUtils.ALLOW_BACKSLASH
    (new system property: org.apache.shiro.web.ALLOW_BACKSLASH)
    
    Fixes: SHIRO-794
---
 .../shiro/web/filter/InvalidRequestFilter.java     | 22 +++++--
 .../java/org/apache/shiro/web/util/WebUtils.java   |  4 +-
 .../web/filter/InvalidRequestFilterTest.groovy     | 48 +++++++++++++--
 .../org/apache/shiro/web/util/WebUtilsTest.groovy  | 52 ++++++++++++++++
 .../apache/shiro/web/RestoreSystemProperties.java  | 69 ++++++++++++++++++++++
 5 files changed, 182 insertions(+), 13 deletions(-)

diff --git a/web/src/main/java/org/apache/shiro/web/filter/InvalidRequestFilter.java b/web/src/main/java/org/apache/shiro/web/filter/InvalidRequestFilter.java
index 3d229e9..63da6d4 100644
--- a/web/src/main/java/org/apache/shiro/web/filter/InvalidRequestFilter.java
+++ b/web/src/main/java/org/apache/shiro/web/filter/InvalidRequestFilter.java
@@ -19,10 +19,12 @@
 
 package org.apache.shiro.web.filter;
 
+import org.apache.shiro.lang.util.StringUtils;
 import org.apache.shiro.web.util.WebUtils;
 
 import javax.servlet.ServletRequest;
 import javax.servlet.ServletResponse;
+import javax.servlet.http.HttpServletRequest;
 import java.util.Arrays;
 import java.util.Collections;
 import java.util.List;
@@ -48,16 +50,24 @@ public class InvalidRequestFilter extends AccessControlFilter {
 
     private boolean blockSemicolon = true;
 
-    private boolean blockBackslash = true;
+    private boolean blockBackslash = !Boolean.getBoolean(WebUtils.ALLOW_BACKSLASH);
 
     private boolean blockNonAscii = true;
 
     @Override
-    protected boolean isAccessAllowed(ServletRequest request, ServletResponse response, Object mappedValue) throws Exception {
-        String uri = WebUtils.toHttp(request).getRequestURI();
-        return !containsSemicolon(uri)
-            && !containsBackslash(uri)
-            && !containsNonAsciiCharacters(uri);
+    protected boolean isAccessAllowed(ServletRequest req, ServletResponse response, Object mappedValue) throws Exception {
+        HttpServletRequest request = WebUtils.toHttp(req);
+        // check the original and decoded values
+        return isValid(request.getRequestURI())      // user request string (not decoded)
+                && isValid(request.getServletPath()) // decoded servlet part
+                && isValid(request.getPathInfo());   // decoded path info (may be null)
+    }
+
+    private boolean isValid(String uri) {
+        return !StringUtils.hasText(uri)
+               || ( !containsSemicolon(uri)
+                 && !containsBackslash(uri)
+                 && !containsNonAsciiCharacters(uri));
     }
 
     @Override
diff --git a/web/src/main/java/org/apache/shiro/web/util/WebUtils.java b/web/src/main/java/org/apache/shiro/web/util/WebUtils.java
index abc27c4..992f7ad 100644
--- a/web/src/main/java/org/apache/shiro/web/util/WebUtils.java
+++ b/web/src/main/java/org/apache/shiro/web/util/WebUtils.java
@@ -57,6 +57,8 @@ public class WebUtils {
     public static final String SERVLET_REQUEST_KEY = ServletRequest.class.getName() + "_SHIRO_THREAD_CONTEXT_KEY";
     public static final String SERVLET_RESPONSE_KEY = ServletResponse.class.getName() + "_SHIRO_THREAD_CONTEXT_KEY";
 
+    public static final String ALLOW_BACKSLASH = "org.apache.shiro.web.ALLOW_BACKSLASH";
+
     /**
      * {@link org.apache.shiro.session.Session Session} key used to save a request and later restore it, for example when redirecting to a
      * requested page after login, equal to {@code shiroSavedRequest}.
@@ -163,7 +165,7 @@ public class WebUtils {
      * @return normalized path
      */
     public static String normalize(String path) {
-        return normalize(path, true);
+        return normalize(path, Boolean.getBoolean(ALLOW_BACKSLASH));
     }
 
     /**
diff --git a/web/src/test/groovy/org/apache/shiro/web/filter/InvalidRequestFilterTest.groovy b/web/src/test/groovy/org/apache/shiro/web/filter/InvalidRequestFilterTest.groovy
index 8d0b1c0..c7a0525 100644
--- a/web/src/test/groovy/org/apache/shiro/web/filter/InvalidRequestFilterTest.groovy
+++ b/web/src/test/groovy/org/apache/shiro/web/filter/InvalidRequestFilterTest.groovy
@@ -19,6 +19,7 @@
 
 package org.apache.shiro.web.filter
 
+import org.apache.shiro.web.RestoreSystemProperties
 import org.junit.Test
 
 import javax.servlet.http.HttpServletRequest
@@ -39,6 +40,25 @@ class InvalidRequestFilterTest {
     }
 
     @Test
+    void systemPropertyAllowBackslash() {
+        RestoreSystemProperties.withProperties(["org.apache.shiro.web.ALLOW_BACKSLASH": "true"]) {
+            InvalidRequestFilter filter = new InvalidRequestFilter()
+            assertThat "filter.blockBackslash expected to be false", !filter.isBlockBackslash()
+        }
+
+        RestoreSystemProperties.withProperties(["org.apache.shiro.web.ALLOW_BACKSLASH": ""]) {
+            InvalidRequestFilter filter = new InvalidRequestFilter()
+            assertThat "filter.blockBackslash expected to be false", filter.isBlockBackslash()
+        }
+
+        RestoreSystemProperties.withProperties(["org.apache.shiro.web.ALLOW_BACKSLASH": "false"]) {
+            InvalidRequestFilter filter = new InvalidRequestFilter()
+            assertThat "filter.blockBackslash expected to be false", filter.isBlockBackslash()
+        }
+    }
+
+
+    @Test
     void testFilterBlocks() {
         InvalidRequestFilter filter = new InvalidRequestFilter()
         assertPathBlocked(filter, "/\\something")
@@ -48,6 +68,9 @@ class InvalidRequestFilterTest {
         assertPathBlocked(filter, "/%3bsomething")
         assertPathBlocked(filter, "/%3Bsomething")
         assertPathBlocked(filter, "/\u0019something")
+
+        assertPathBlocked(filter, "/something", "/;something")
+        assertPathBlocked(filter, "/something", "/something", "/;")
     }
 
     @Test
@@ -61,6 +84,9 @@ class InvalidRequestFilterTest {
         assertPathBlocked(filter, "/%3bsomething")
         assertPathBlocked(filter, "/%3Bsomething")
         assertPathBlocked(filter, "/\u0019something")
+
+        assertPathAllowed(filter, "/something", "/\\something")
+        assertPathAllowed(filter, "/something", "/something", "/\\")
     }
 
     @Test
@@ -74,6 +100,9 @@ class InvalidRequestFilterTest {
         assertPathBlocked(filter, "/%3bsomething")
         assertPathBlocked(filter, "/%3Bsomething")
         assertPathAllowed(filter, "/\u0019something")
+
+        assertPathAllowed(filter, "/something", "/\u0019something")
+        assertPathAllowed(filter, "/something", "/something", "/\u0019")
     }
     @Test
     void testFilterAllowsSemicolon() {
@@ -86,20 +115,27 @@ class InvalidRequestFilterTest {
         assertPathAllowed(filter, "/%3bsomething")
         assertPathAllowed(filter, "/%3Bsomething")
         assertPathBlocked(filter, "/\u0019something")
+
+        assertPathAllowed(filter, "/something", "/;something")
+        assertPathAllowed(filter, "/something", "/something", "/;")
     }
 
 
-    static void assertPathBlocked(InvalidRequestFilter filter, String path) {
-        assertThat "Expected path '${path}', to be blocked", !filter.isAccessAllowed(mockRequest(path), null, null)
+    static void assertPathBlocked(InvalidRequestFilter filter, String requestUri, String servletPath = requestUri, String pathInfo = null) {
+        assertThat "Expected path '${requestUri}', to be blocked", !filter.isAccessAllowed(mockRequest(requestUri, servletPath, pathInfo), null, null)
     }
 
-    static void assertPathAllowed(InvalidRequestFilter filter, String path) {
-        assertThat "Expected path '${path}', to be allowed", filter.isAccessAllowed(mockRequest(path), null, null)
+    static void assertPathAllowed(InvalidRequestFilter filter, String requestUri, String servletPath = requestUri, String pathInfo = null) {
+        assertThat "Expected requestUri '${requestUri}', to be allowed", filter.isAccessAllowed(mockRequest(requestUri, servletPath, pathInfo), null, null)
     }
 
-    static HttpServletRequest mockRequest(String path) {
+    static HttpServletRequest mockRequest(String requestUri, String servletPath, String pathInfo) {
         HttpServletRequest request = mock(HttpServletRequest)
-        expect(request.getRequestURI()).andReturn(path)
+        expect(request.getRequestURI()).andReturn(requestUri)
+        expect(request.getServletPath()).andReturn(servletPath).anyTimes()
+        expect(request.getPathInfo()).andReturn(pathInfo).anyTimes()
+        expect(request.getAttribute("javax.servlet.include.servlet_path")).andReturn(servletPath)
+        expect(request.getAttribute("javax.servlet.include.path_info")).andReturn(pathInfo)
         replay(request)
         return request
     }
diff --git a/web/src/test/groovy/org/apache/shiro/web/util/WebUtilsTest.groovy b/web/src/test/groovy/org/apache/shiro/web/util/WebUtilsTest.groovy
index 7956a10..b501605 100644
--- a/web/src/test/groovy/org/apache/shiro/web/util/WebUtilsTest.groovy
+++ b/web/src/test/groovy/org/apache/shiro/web/util/WebUtilsTest.groovy
@@ -18,12 +18,15 @@
  */
 package org.apache.shiro.web.util
 
+import org.apache.shiro.web.RestoreSystemProperties
+import org.hamcrest.CoreMatchers
 import org.junit.Test
 
 import javax.servlet.http.HttpServletRequest
 
 import static org.easymock.EasyMock.*
 import static org.junit.Assert.*
+import static org.hamcrest.CoreMatchers.*
 
 /**
  * Tests for {@link WebUtils}.
@@ -193,6 +196,55 @@ public class WebUtilsTest {
         doTestGetRequestURI("/context path/foobar", "/context path/foobar");
     }
 
+    @Test
+    void testNormalize() {
+        doNormalizeTest"/foobar", "/foobar"
+        doNormalizeTest "/foobar/", "/foobar/"
+        doNormalizeTest"", "/"
+        doNormalizeTest"foobar", "/foobar"
+        doNormalizeTest"//foobar", "/foobar"
+        doNormalizeTest"//foobar///", "/foobar/"
+        doNormalizeTest"/context-path/foobar", "/context-path/foobar"
+        doNormalizeTest"/context-path/foobar/", "/context-path/foobar/"
+        doNormalizeTest"//context-path/foobar", "/context-path/foobar"
+        doNormalizeTest"//context-path//foobar" ,"/context-path/foobar"
+        doNormalizeTest"//context-path/remove-one/remove-two/../../././/foobar", "/context-path/foobar"
+        doNormalizeTest"//context-path//../../././/foobar", null
+        doNormalizeTest"/context path/foobar", "/context path/foobar"
+
+        doNormalizeTest"/context path/\\foobar", "/context path/\\foobar"
+        doNormalizeTest"//context-path\\..\\../.\\.\\foobar", "/context-path\\..\\../.\\.\\foobar"
+        doNormalizeTest"//context-path\\..\\..\\.\\.\\foobar", "/context-path\\..\\..\\.\\.\\foobar"
+        doNormalizeTest"\\context-path\\..\\foobar", "/\\context-path\\..\\foobar"
+    }
+
+    @Test
+    void testNormalize_allowBackslashes() {
+        RestoreSystemProperties.withProperties(["org.apache.shiro.web.ALLOW_BACKSLASH": "true"]) {
+            doNormalizeTest"/foobar", "/foobar"
+            doNormalizeTest "/foobar/", "/foobar/"
+            doNormalizeTest"", "/"
+            doNormalizeTest"foobar", "/foobar"
+            doNormalizeTest"//foobar", "/foobar"
+            doNormalizeTest"//foobar///", "/foobar/"
+            doNormalizeTest"/context-path/foobar", "/context-path/foobar"
+            doNormalizeTest"/context-path/foobar/", "/context-path/foobar/"
+            doNormalizeTest"//context-path/foobar", "/context-path/foobar"
+            doNormalizeTest"//context-path//foobar" ,"/context-path/foobar"
+            doNormalizeTest"//context-path/remove-one/remove-two/../../././/foobar", "/context-path/foobar"
+            doNormalizeTest"//context-path//../../././/foobar", null
+            doNormalizeTest"/context path/foobar", "/context path/foobar"
+            doNormalizeTest"/context path/\\foobar", "/context path/foobar"
+            doNormalizeTest"//context-path\\..\\..\\.\\.\\foobar", null
+            doNormalizeTest"\\context-path\\..\\foobar", "/foobar"
+
+        }
+    }
+
+    void doNormalizeTest(String path, String expected) {
+        assertThat WebUtils.normalize(path), equalTo(expected)
+    }
+
     void doTestGetPathWithinApplication(String servletPath, String pathInfo, String expectedValue) {
 
         def request = createMock(HttpServletRequest)
diff --git a/web/src/test/java/org/apache/shiro/web/RestoreSystemProperties.java b/web/src/test/java/org/apache/shiro/web/RestoreSystemProperties.java
new file mode 100644
index 0000000..882e2e9
--- /dev/null
+++ b/web/src/test/java/org/apache/shiro/web/RestoreSystemProperties.java
@@ -0,0 +1,69 @@
+/*
+ * 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.shiro.web;
+
+import groovy.lang.Closure;
+
+import java.io.Closeable;
+import java.util.Collections;
+import java.util.Map;
+import java.util.Properties;
+
+/**
+ * Wrapper that will restore System properties after test methods.
+ *
+ * Based on: https://github.com/stefanbirkner/system-rules/blob/master/src/main/java/org/junit/contrib/java/lang/system/RestoreSystemProperties.java
+ */
+public class RestoreSystemProperties implements Closeable {
+
+    private final Properties originalProperties;
+
+    public RestoreSystemProperties() {
+        originalProperties = System.getProperties();
+        System.setProperties(copyOf(originalProperties));
+    }
+
+    public void restore() {
+        System.setProperties(originalProperties);
+    }
+
+    private Properties copyOf(Properties source) {
+        Properties copy = new Properties();
+        copy.putAll(source);
+        return copy;
+    }
+
+    public static <T> T withProperties(Closure<T> closure) {
+        return withProperties(Collections.emptyMap(), closure);
+    }
+
+    public static <T> T withProperties(Map<String, String> properties, Closure<T> closure) {
+
+        try (RestoreSystemProperties restoreSystemProperties = new RestoreSystemProperties()) {
+            properties.forEach(System::setProperty);
+
+            return closure.call();
+        }
+    }
+
+    @Override
+    public void close() {
+        restore();
+    }
+}


[shiro] 01/03: Add ShiroUrlHelper and related Spring configuration

Posted by bd...@apache.org.
This is an automated email from the ASF dual-hosted git repository.

bdemers pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/shiro.git

commit 16fc47ae44e330297ed24f080a20d211c2666667
Author: Brian Demers <bd...@apache.org>
AuthorDate: Thu Sep 10 18:08:47 2020 -0400

    Add ShiroUrlHelper and related Spring configuration
    
    and related tests
---
 .../samples/spring/config/ApplicationConfig.java   |  4 +-
 .../samples/spring/config/JspViewsConfig.java      |  4 +-
 .../autoconfigure/ShiroWebAutoConfiguration.java   | 10 +++++
 .../ShiroWebMvcAutoConfiguration.java              | 32 +++++++++++++++
 .../src/main/resources/META-INF/spring.factories   |  3 +-
 support/spring/pom.xml                             | 15 ++++---
 .../shiro/spring/web/ShiroUrlPathHelper.java       | 41 +++++++++++++++++++
 .../web/config/AbstractShiroWebConfiguration.java  |  5 +++
 .../web/config/ShiroRequestMappingConfig.java      | 31 +++++++++++++++
 .../spring/web/config/ShiroWebConfiguration.java   |  7 ++++
 .../shiro/spring/web/ShiroUrlPathHelperTest.groovy | 46 ++++++++++++++++++++++
 11 files changed, 189 insertions(+), 9 deletions(-)

diff --git a/samples/spring-mvc/src/main/java/org/apache/shiro/samples/spring/config/ApplicationConfig.java b/samples/spring-mvc/src/main/java/org/apache/shiro/samples/spring/config/ApplicationConfig.java
index 67a5cca..9c06eae 100644
--- a/samples/spring-mvc/src/main/java/org/apache/shiro/samples/spring/config/ApplicationConfig.java
+++ b/samples/spring-mvc/src/main/java/org/apache/shiro/samples/spring/config/ApplicationConfig.java
@@ -30,6 +30,7 @@ import org.apache.shiro.spring.config.ShiroBeanConfiguration;
 import org.apache.shiro.spring.remoting.SecureRemoteInvocationExecutor;
 import org.apache.shiro.spring.web.config.DefaultShiroFilterChainDefinition;
 import org.apache.shiro.spring.web.config.ShiroFilterChainDefinition;
+import org.apache.shiro.spring.web.config.ShiroRequestMappingConfig;
 import org.apache.shiro.spring.web.config.ShiroWebConfiguration;
 import org.apache.shiro.spring.web.config.ShiroWebFilterConfiguration;
 import org.springframework.context.annotation.Bean;
@@ -53,7 +54,8 @@ import static org.apache.shiro.web.filter.mgt.DefaultFilter.anon;
         ShiroWebConfiguration.class,
         ShiroWebFilterConfiguration.class,
         JspViewsConfig.class,
-        RemotingServletConfig.class})
+        RemotingServletConfig.class,
+        ShiroRequestMappingConfig.class})
 @ComponentScan("org.apache.shiro.samples.spring")
 public class ApplicationConfig {
 
diff --git a/samples/spring-mvc/src/main/java/org/apache/shiro/samples/spring/config/JspViewsConfig.java b/samples/spring-mvc/src/main/java/org/apache/shiro/samples/spring/config/JspViewsConfig.java
index 551089c..34f9912 100644
--- a/samples/spring-mvc/src/main/java/org/apache/shiro/samples/spring/config/JspViewsConfig.java
+++ b/samples/spring-mvc/src/main/java/org/apache/shiro/samples/spring/config/JspViewsConfig.java
@@ -25,7 +25,7 @@ import org.springframework.core.annotation.Order;
 import org.springframework.web.servlet.ViewResolver;
 import org.springframework.web.servlet.config.annotation.EnableWebMvc;
 import org.springframework.web.servlet.config.annotation.ResourceHandlerRegistry;
-import org.springframework.web.servlet.config.annotation.WebMvcConfigurerAdapter;
+import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
 import org.springframework.web.servlet.view.InternalResourceViewResolver;
 import org.springframework.web.servlet.view.JstlView;
 
@@ -35,7 +35,7 @@ import org.springframework.web.servlet.view.JstlView;
 @Configuration
 @ComponentScan("org.apache.shiro.samples.spring")
 @EnableWebMvc
-public class JspViewsConfig extends WebMvcConfigurerAdapter {
+public class JspViewsConfig implements WebMvcConfigurer {
 
     @Bean
     @Order(1)
diff --git a/support/spring-boot/spring-boot-web-starter/src/main/java/org/apache/shiro/spring/config/web/autoconfigure/ShiroWebAutoConfiguration.java b/support/spring-boot/spring-boot-web-starter/src/main/java/org/apache/shiro/spring/config/web/autoconfigure/ShiroWebAutoConfiguration.java
index 4ab440c..3b89b63 100644
--- a/support/spring-boot/spring-boot-web-starter/src/main/java/org/apache/shiro/spring/config/web/autoconfigure/ShiroWebAutoConfiguration.java
+++ b/support/spring-boot/spring-boot-web-starter/src/main/java/org/apache/shiro/spring/config/web/autoconfigure/ShiroWebAutoConfiguration.java
@@ -33,9 +33,11 @@ import org.apache.shiro.session.mgt.SessionFactory;
 import org.apache.shiro.session.mgt.SessionManager;
 import org.apache.shiro.session.mgt.eis.SessionDAO;
 import org.apache.shiro.spring.boot.autoconfigure.ShiroAutoConfiguration;
+import org.apache.shiro.spring.web.ShiroUrlPathHelper;
 import org.apache.shiro.spring.web.config.AbstractShiroWebConfiguration;
 import org.apache.shiro.spring.web.config.ShiroFilterChainDefinition;
 import org.apache.shiro.web.servlet.Cookie;
+import org.springframework.boot.autoconfigure.AutoConfigureAfter;
 import org.springframework.boot.autoconfigure.AutoConfigureBefore;
 import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
 import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
@@ -47,6 +49,7 @@ import org.springframework.context.annotation.Configuration;
  */
 @Configuration
 @AutoConfigureBefore(ShiroAutoConfiguration.class)
+@AutoConfigureAfter(ShiroWebMvcAutoConfiguration.class)
 @ConditionalOnProperty(name = "shiro.web.enabled", matchIfMissing = true)
 public class ShiroWebAutoConfiguration extends AbstractShiroWebConfiguration {
 
@@ -147,4 +150,11 @@ public class ShiroWebAutoConfiguration extends AbstractShiroWebConfiguration {
     protected ShiroFilterChainDefinition shiroFilterChainDefinition() {
         return super.shiroFilterChainDefinition();
     }
+
+    @Bean
+    @ConditionalOnMissingBean
+    @Override
+    protected ShiroUrlPathHelper shiroUrlPathHelper() {
+        return super.shiroUrlPathHelper();
+    }
 }
diff --git a/support/spring-boot/spring-boot-web-starter/src/main/java/org/apache/shiro/spring/config/web/autoconfigure/ShiroWebMvcAutoConfiguration.java b/support/spring-boot/spring-boot-web-starter/src/main/java/org/apache/shiro/spring/config/web/autoconfigure/ShiroWebMvcAutoConfiguration.java
new file mode 100644
index 0000000..26fdeb7
--- /dev/null
+++ b/support/spring-boot/spring-boot-web-starter/src/main/java/org/apache/shiro/spring/config/web/autoconfigure/ShiroWebMvcAutoConfiguration.java
@@ -0,0 +1,32 @@
+/*
+ * 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.shiro.spring.config.web.autoconfigure;
+
+import org.apache.shiro.spring.web.config.ShiroRequestMappingConfig;
+import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
+import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
+import org.springframework.context.annotation.Configuration;
+import org.springframework.context.annotation.Import;
+import org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerMapping;
+
+@Configuration
+@ConditionalOnClass(RequestMappingHandlerMapping.class)
+@Import(ShiroRequestMappingConfig.class)
+@ConditionalOnProperty(name = "shiro.web.enabled", matchIfMissing = true)
+public class ShiroWebMvcAutoConfiguration { }
diff --git a/support/spring-boot/spring-boot-web-starter/src/main/resources/META-INF/spring.factories b/support/spring-boot/spring-boot-web-starter/src/main/resources/META-INF/spring.factories
index b69324a..328062d 100644
--- a/support/spring-boot/spring-boot-web-starter/src/main/resources/META-INF/spring.factories
+++ b/support/spring-boot/spring-boot-web-starter/src/main/resources/META-INF/spring.factories
@@ -1,3 +1,4 @@
 org.springframework.boot.autoconfigure.EnableAutoConfiguration = \
   org.apache.shiro.spring.config.web.autoconfigure.ShiroWebAutoConfiguration,\
-  org.apache.shiro.spring.config.web.autoconfigure.ShiroWebFilterConfiguration
+  org.apache.shiro.spring.config.web.autoconfigure.ShiroWebFilterConfiguration, \
+  org.apache.shiro.spring.config.web.autoconfigure.ShiroWebMvcAutoConfiguration
diff --git a/support/spring/pom.xml b/support/spring/pom.xml
index 254373f..78d8b65 100644
--- a/support/spring/pom.xml
+++ b/support/spring/pom.xml
@@ -50,6 +50,16 @@
             <artifactId>spring-context</artifactId>
             <scope>provided</scope>
         </dependency>
+        <dependency>
+            <groupId>org.springframework</groupId>
+            <artifactId>spring-web</artifactId>
+            <optional>true</optional>
+        </dependency>
+        <dependency>
+            <groupId>org.springframework</groupId>
+            <artifactId>spring-webmvc</artifactId>
+            <optional>true</optional>
+        </dependency>
         <!-- Test dependencies -->
         <dependency>
             <groupId>org.slf4j</groupId>
@@ -72,11 +82,6 @@
             <scope>test</scope>
         </dependency>
         <dependency>
-            <groupId>org.springframework</groupId>
-            <artifactId>spring-web</artifactId>
-            <scope>test</scope>
-        </dependency>
-        <dependency>
             <groupId>org.apache.shiro</groupId>
             <artifactId>shiro-aspectj</artifactId>
             <scope>test</scope>
diff --git a/support/spring/src/main/java/org/apache/shiro/spring/web/ShiroUrlPathHelper.java b/support/spring/src/main/java/org/apache/shiro/spring/web/ShiroUrlPathHelper.java
new file mode 100644
index 0000000..4b5ddbd
--- /dev/null
+++ b/support/spring/src/main/java/org/apache/shiro/spring/web/ShiroUrlPathHelper.java
@@ -0,0 +1,41 @@
+/*
+ * 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.shiro.spring.web;
+
+import org.apache.shiro.web.util.WebUtils;
+import org.springframework.web.util.UrlPathHelper;
+
+import javax.servlet.http.HttpServletRequest;
+
+/**
+ * A Spring UrlPathHelper that uses Shiro's path resolution logic.
+ * @since 1.7.0
+ */
+public class ShiroUrlPathHelper extends UrlPathHelper {
+
+    @Override
+    public String getPathWithinApplication(HttpServletRequest request) {
+        return WebUtils.getPathWithinApplication(request);
+    }
+
+    @Override
+    public String getPathWithinServletMapping(HttpServletRequest request) {
+        return WebUtils.getPathWithinApplication(request);
+    }
+}
diff --git a/support/spring/src/main/java/org/apache/shiro/spring/web/config/AbstractShiroWebConfiguration.java b/support/spring/src/main/java/org/apache/shiro/spring/web/config/AbstractShiroWebConfiguration.java
index ae2afb5..5ed98d8 100644
--- a/support/spring/src/main/java/org/apache/shiro/spring/web/config/AbstractShiroWebConfiguration.java
+++ b/support/spring/src/main/java/org/apache/shiro/spring/web/config/AbstractShiroWebConfiguration.java
@@ -24,6 +24,7 @@ import org.apache.shiro.mgt.SessionsSecurityManager;
 import org.apache.shiro.mgt.SubjectFactory;
 import org.apache.shiro.session.mgt.SessionManager;
 import org.apache.shiro.spring.config.AbstractShiroConfiguration;
+import org.apache.shiro.spring.web.ShiroUrlPathHelper;
 import org.apache.shiro.web.mgt.CookieRememberMeManager;
 import org.apache.shiro.web.mgt.DefaultWebSecurityManager;
 import org.apache.shiro.web.mgt.DefaultWebSessionStorageEvaluator;
@@ -181,4 +182,8 @@ public class AbstractShiroWebConfiguration extends AbstractShiroConfiguration {
         chainDefinition.addPathDefinition("/**", "authc");
         return chainDefinition;
     }
+
+    protected ShiroUrlPathHelper shiroUrlPathHelper() {
+        return new ShiroUrlPathHelper();
+    }
 }
diff --git a/support/spring/src/main/java/org/apache/shiro/spring/web/config/ShiroRequestMappingConfig.java b/support/spring/src/main/java/org/apache/shiro/spring/web/config/ShiroRequestMappingConfig.java
new file mode 100644
index 0000000..317cb4d
--- /dev/null
+++ b/support/spring/src/main/java/org/apache/shiro/spring/web/config/ShiroRequestMappingConfig.java
@@ -0,0 +1,31 @@
+/*
+ * 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.shiro.spring.web.config;
+
+import org.apache.shiro.spring.web.ShiroUrlPathHelper;
+import org.springframework.context.annotation.Configuration;
+import org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerMapping;
+
+@Configuration
+public class ShiroRequestMappingConfig {
+
+    public ShiroRequestMappingConfig(RequestMappingHandlerMapping requestMappingHandlerMapping) {
+        requestMappingHandlerMapping.setUrlPathHelper(new ShiroUrlPathHelper());
+    }
+}
diff --git a/support/spring/src/main/java/org/apache/shiro/spring/web/config/ShiroWebConfiguration.java b/support/spring/src/main/java/org/apache/shiro/spring/web/config/ShiroWebConfiguration.java
index dc57b22..952a26a 100644
--- a/support/spring/src/main/java/org/apache/shiro/spring/web/config/ShiroWebConfiguration.java
+++ b/support/spring/src/main/java/org/apache/shiro/spring/web/config/ShiroWebConfiguration.java
@@ -26,6 +26,7 @@ import org.apache.shiro.realm.Realm;
 import org.apache.shiro.session.mgt.SessionFactory;
 import org.apache.shiro.session.mgt.SessionManager;
 import org.apache.shiro.session.mgt.eis.SessionDAO;
+import org.apache.shiro.spring.web.ShiroUrlPathHelper;
 import org.apache.shiro.web.servlet.Cookie;
 import org.springframework.context.annotation.Bean;
 import org.springframework.context.annotation.Configuration;
@@ -122,4 +123,10 @@ public class ShiroWebConfiguration extends AbstractShiroWebConfiguration {
     protected ShiroFilterChainDefinition shiroFilterChainDefinition() {
         return super.shiroFilterChainDefinition();
     }
+
+    @Bean
+    @Override
+    protected ShiroUrlPathHelper shiroUrlPathHelper() {
+        return super.shiroUrlPathHelper();
+    }
 }
diff --git a/support/spring/src/test/groovy/org/apache/shiro/spring/web/ShiroUrlPathHelperTest.groovy b/support/spring/src/test/groovy/org/apache/shiro/spring/web/ShiroUrlPathHelperTest.groovy
new file mode 100644
index 0000000..08eeb79
--- /dev/null
+++ b/support/spring/src/test/groovy/org/apache/shiro/spring/web/ShiroUrlPathHelperTest.groovy
@@ -0,0 +1,46 @@
+/*
+ * 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.shiro.spring.web
+
+import org.junit.Test
+import org.springframework.mock.web.MockHttpServletRequest
+import org.springframework.web.util.UrlPathHelper
+
+import static org.hamcrest.MatcherAssert.assertThat
+import static org.hamcrest.Matchers.equalTo
+
+/**
+ * Tests a couple known differences between the stock and the ShiroUrlPathHelper
+ */
+class ShiroUrlPathHelperTest {
+
+    @Test
+    void testGetPathWithinApplication() {
+        MockHttpServletRequest request = new MockHttpServletRequest("GET", "/foo/%2e%2e")
+        assertThat new UrlPathHelper().getPathWithinApplication(request), equalTo("/foo/..")
+        assertThat new ShiroUrlPathHelper().getPathWithinApplication(request), equalTo("/")
+    }
+
+    @Test
+    void testGetPathWithinServletMapping() {
+        MockHttpServletRequest request = new MockHttpServletRequest("GET", "/foo/%2e%2e")
+        assertThat new UrlPathHelper().getPathWithinServletMapping(request), equalTo("/foo/..")
+        assertThat new ShiroUrlPathHelper().getPathWithinServletMapping(request), equalTo("/")
+    }
+}
\ No newline at end of file