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

lprimak pushed a commit to branch 3.x
in repository https://gitbox.apache.org/repos/asf/shiro.git


The following commit(s) were added to refs/heads/3.x by this push:
     new 6326d86a3 enh[3.x]: Adds default NoAccess configuration to the default 
filter chain (#2461)
6326d86a3 is described below

commit 6326d86a3c3b6e8ad4e25932fb89a353d37afbcf
Author: Lenny Primak <[email protected]>
AuthorDate: Sat Jan 31 15:02:26 2026 -0600

    enh[3.x]: Adds default NoAccess configuration to the default filter chain 
(#2461)
    
    * enh: Adds default NoAccess configuration to the default filter chain
    
    * added feature flag
    
    * chore: javax -> jakarta
    
    ---------
    
    Co-authored-by: Brian Demers <[email protected]>
---
 samples/web/src/main/webapp/WEB-INF/shiro.ini      |  3 ++
 .../org/apache/shiro/guice/web/ShiroWebModule.java | 23 ++++++++++-
 .../web/ConfiguredGlobalFiltersTest.groovy         |  3 +-
 .../web/DisabledGlobalFiltersTest.groovy           |  7 +++-
 .../web/ShiroWebSpringAutoConfigurationTest.groovy |  4 +-
 .../shiro/spring/web/ShiroFilterFactoryBean.java   | 23 ++++++++++-
 .../spring/web/ShiroFilterFactoryBeanTest.java     |  7 ++--
 .../spring/web/ShiroFilterFactoryBeanTest.xml      |  2 +-
 .../web/config/IniFilterChainResolverFactory.java  | 15 ++++++-
 .../shiro/web/filter/authc/NoAccessFilter.java     | 48 ++++++++++++++++++++++
 .../apache/shiro/web/filter/mgt/DefaultFilter.java |  8 +++-
 .../web/filter/mgt/DefaultFilterChainManager.java  |  7 ++--
 .../shiro/web/filter/mgt/FilterChainManager.java   | 14 ++++++-
 .../mgt/DefaultFilterChainManagerTest.groovy       |  7 ++--
 14 files changed, 148 insertions(+), 23 deletions(-)

diff --git a/samples/web/src/main/webapp/WEB-INF/shiro.ini 
b/samples/web/src/main/webapp/WEB-INF/shiro.ini
index 6465310aa..9fa44a54a 100644
--- a/samples/web/src/main/webapp/WEB-INF/shiro.ini
+++ b/samples/web/src/main/webapp/WEB-INF/shiro.ini
@@ -60,3 +60,6 @@ goodguy = winnebago:drive:eagle5
 /logout = logout
 /account/** = authc
 /remoting/** = authc, roles[b2bClient], perms["remote:invoke:lan,wan"]
+/favicon.ico = anon
+/style.css = anon
+/** = authc
diff --git 
a/support/guice/src/main/java/org/apache/shiro/guice/web/ShiroWebModule.java 
b/support/guice/src/main/java/org/apache/shiro/guice/web/ShiroWebModule.java
index b3917c163..4c1806161 100644
--- a/support/guice/src/main/java/org/apache/shiro/guice/web/ShiroWebModule.java
+++ b/support/guice/src/main/java/org/apache/shiro/guice/web/ShiroWebModule.java
@@ -38,6 +38,7 @@ import 
org.apache.shiro.web.filter.authc.BasicHttpAuthenticationFilter;
 import org.apache.shiro.web.filter.authc.BearerHttpAuthenticationFilter;
 import org.apache.shiro.web.filter.authc.FormAuthenticationFilter;
 import org.apache.shiro.web.filter.authc.LogoutFilter;
+import org.apache.shiro.web.filter.authc.NoAccessFilter;
 import org.apache.shiro.web.filter.authc.UserFilter;
 import org.apache.shiro.web.filter.authz.HttpMethodPermissionFilter;
 import org.apache.shiro.web.filter.authz.IpFilter;
@@ -62,7 +63,6 @@ import java.util.LinkedHashMap;
 import java.util.List;
 import java.util.Map;
 
-@SuppressWarnings("checkstyle:JavadocVariable")
 /**
  * Sets up Shiro lifecycles within Guice, enables the injecting of Shiro 
objects, and binds a default
  * {@link org.apache.shiro.web.mgt.WebSecurityManager},
@@ -73,21 +73,38 @@ import java.util.Map;
  * Also provides for the configuring of filter chains and binds a
  * {@link org.apache.shiro.web.filter.mgt.FilterChainResolver} with that 
information.
  */
+@SuppressWarnings("checkstyle:JavadocVariable")
 public abstract class ShiroWebModule extends ShiroModule {
+    @SuppressWarnings({"UnusedDeclaration"})
     public static final Key<AnonymousFilter> ANON = 
Key.get(AnonymousFilter.class);
+    @SuppressWarnings({"UnusedDeclaration"})
     public static final Key<FormAuthenticationFilter> AUTHC = 
Key.get(FormAuthenticationFilter.class);
+    @SuppressWarnings({"UnusedDeclaration"})
     public static final Key<BasicHttpAuthenticationFilter> AUTHC_BASIC = 
Key.get(BasicHttpAuthenticationFilter.class);
+    @SuppressWarnings({"UnusedDeclaration"})
     public static final Key<BearerHttpAuthenticationFilter> AUTHC_BEARER = 
Key.get(BearerHttpAuthenticationFilter.class);
+    @SuppressWarnings({"UnusedDeclaration"})
     public static final Key<NoSessionCreationFilter> NO_SESSION_CREATION = 
Key.get(NoSessionCreationFilter.class);
+    @SuppressWarnings({"UnusedDeclaration"})
     public static final Key<LogoutFilter> LOGOUT = Key.get(LogoutFilter.class);
+    @SuppressWarnings({"UnusedDeclaration"})
     public static final Key<PermissionsAuthorizationFilter> PERMS = 
Key.get(PermissionsAuthorizationFilter.class);
+    @SuppressWarnings({"UnusedDeclaration"})
     public static final Key<PortFilter> PORT = Key.get(PortFilter.class);
+    @SuppressWarnings({"UnusedDeclaration"})
     public static final Key<HttpMethodPermissionFilter> REST = 
Key.get(HttpMethodPermissionFilter.class);
+    @SuppressWarnings({"UnusedDeclaration"})
     public static final Key<RolesAuthorizationFilter> ROLES = 
Key.get(RolesAuthorizationFilter.class);
+    @SuppressWarnings({"UnusedDeclaration"})
     public static final Key<SslFilter> SSL = Key.get(SslFilter.class);
+    @SuppressWarnings({"UnusedDeclaration"})
     public static final Key<IpFilter> IP = Key.get(IpFilter.class);
+    @SuppressWarnings({"UnusedDeclaration"})
     public static final Key<UserFilter> USER = Key.get(UserFilter.class);
+    @SuppressWarnings({"UnusedDeclaration"})
     public static final Key<InvalidRequestFilter> INVALID_REQUEST = 
Key.get(InvalidRequestFilter.class);
+    @SuppressWarnings({"UnusedDeclaration"})
+    public static final Key<NoAccessFilter> NO_ACCESS = 
Key.get(NoAccessFilter.class);
 
     static final String NAME = "SHIRO";
 
@@ -107,6 +124,7 @@ public abstract class ShiroWebModule extends ShiroModule {
         binder.install(guiceFilterModule());
     }
 
+    @SuppressWarnings({"UnusedDeclaration"})
     public static void bindGuiceFilter(final String pattern, Binder binder) {
         binder.install(guiceFilterModule(pattern));
     }
@@ -343,6 +361,7 @@ public abstract class ShiroWebModule extends ShiroModule {
      * @return A FilterConfig used to map a String path to this configuration.
      * @since 1.4
      */
+    @SuppressWarnings({"UnusedDeclaration"})
     protected static <T extends Filter> FilterConfig<T> filterConfig(Class<T> 
type, String configValue) {
         return filterConfig(Key.get(type), configValue);
     }
@@ -434,11 +453,13 @@ public abstract class ShiroWebModule extends ShiroModule {
         return new FilterConfigKey<T>(baseKey, configValue);
     }
 
+    @SuppressWarnings({"UnusedDeclaration"})
     @Deprecated
     protected static <T extends PathMatchingFilter> Key<T> 
config(TypeLiteral<T> typeLiteral, String configValue) {
         return config(Key.get(typeLiteral), configValue);
     }
 
+    @SuppressWarnings({"UnusedDeclaration"})
     @Deprecated
     protected static <T extends PathMatchingFilter> Key<T> config(Class<T> 
type, String configValue) {
         return config(Key.get(type), configValue);
diff --git 
a/support/spring-boot/spring-boot-starter/src/test/groovy/org/apache/shiro/spring/boot/autoconfigure/web/ConfiguredGlobalFiltersTest.groovy
 
b/support/spring-boot/spring-boot-starter/src/test/groovy/org/apache/shiro/spring/boot/autoconfigure/web/ConfiguredGlobalFiltersTest.groovy
index c482a21a3..4120b6d1f 100644
--- 
a/support/spring-boot/spring-boot-starter/src/test/groovy/org/apache/shiro/spring/boot/autoconfigure/web/ConfiguredGlobalFiltersTest.groovy
+++ 
b/support/spring-boot/spring-boot-starter/src/test/groovy/org/apache/shiro/spring/boot/autoconfigure/web/ConfiguredGlobalFiltersTest.groovy
@@ -80,7 +80,8 @@ class ConfiguredGlobalFiltersTest {
         NamedFilterList allChain = filterChainManager.getChain("/**")
         assertThat allChain, contains(
                 instanceOf(DefaultFilter.invalidRequest.filterClass),
-                instanceOf(DefaultFilter.port.filterClass))
+                instanceOf(DefaultFilter.port.filterClass),
+                instanceOf(DefaultFilter.noAccess.filterClass))
 
         InvalidRequestFilter invalidRequest = allChain.get(0)
         assertThat "Expected invalidRequest.blockBackslash to be false", 
!invalidRequest.isBlockBackslash()
diff --git 
a/support/spring-boot/spring-boot-starter/src/test/groovy/org/apache/shiro/spring/boot/autoconfigure/web/DisabledGlobalFiltersTest.groovy
 
b/support/spring-boot/spring-boot-starter/src/test/groovy/org/apache/shiro/spring/boot/autoconfigure/web/DisabledGlobalFiltersTest.groovy
index 56b93b685..2df014990 100644
--- 
a/support/spring-boot/spring-boot-starter/src/test/groovy/org/apache/shiro/spring/boot/autoconfigure/web/DisabledGlobalFiltersTest.groovy
+++ 
b/support/spring-boot/spring-boot-starter/src/test/groovy/org/apache/shiro/spring/boot/autoconfigure/web/DisabledGlobalFiltersTest.groovy
@@ -19,6 +19,7 @@
 package org.apache.shiro.spring.boot.autoconfigure.web
 
 import 
org.apache.shiro.spring.boot.autoconfigure.web.application.ShiroWebAutoConfigurationTestApplication
+import org.apache.shiro.web.filter.mgt.DefaultFilter
 import org.apache.shiro.web.filter.mgt.DefaultFilterChainManager
 import org.apache.shiro.web.servlet.AbstractShiroFilter
 import org.junit.jupiter.api.Test
@@ -30,7 +31,9 @@ import org.springframework.context.annotation.Configuration
 import org.springframework.test.context.junit.jupiter.SpringExtension
 
 import static org.hamcrest.MatcherAssert.assertThat
-import static org.hamcrest.Matchers.*
+import static org.hamcrest.Matchers.contains
+import static org.hamcrest.Matchers.equalTo
+import static org.hamcrest.Matchers.instanceOf
 
 @ExtendWith(SpringExtension.class)
 @SpringBootTest(classes = [ShiroWebAutoConfigurationTestApplication, Config])
@@ -57,6 +60,6 @@ class DisabledGlobalFiltersTest {
         // default config set
         assertThat filterChainManager.globalFilterNames, equalTo([])
         // default route configured
-        assertThat filterChainManager.getChain("/**"), nullValue()
+        assertThat filterChainManager.getChain("/**"), 
contains(instanceOf(DefaultFilter.noAccess.filterClass))
     }
 }
diff --git 
a/support/spring-boot/spring-boot-starter/src/test/groovy/org/apache/shiro/spring/boot/autoconfigure/web/ShiroWebSpringAutoConfigurationTest.groovy
 
b/support/spring-boot/spring-boot-starter/src/test/groovy/org/apache/shiro/spring/boot/autoconfigure/web/ShiroWebSpringAutoConfigurationTest.groovy
index 017336eb1..8627ccbc1 100644
--- 
a/support/spring-boot/spring-boot-starter/src/test/groovy/org/apache/shiro/spring/boot/autoconfigure/web/ShiroWebSpringAutoConfigurationTest.groovy
+++ 
b/support/spring-boot/spring-boot-starter/src/test/groovy/org/apache/shiro/spring/boot/autoconfigure/web/ShiroWebSpringAutoConfigurationTest.groovy
@@ -82,7 +82,9 @@ class ShiroWebSpringAutoConfigurationTest extends 
AbstractJUnit4SpringContextTes
         // default config set
         assertThat filterChainManager.globalFilterNames, 
equalTo([DefaultFilter.invalidRequest.name()])
         // default route configured
-        assertThat filterChainManager.getChain("/**"), 
contains(instanceOf(DefaultFilter.invalidRequest.filterClass))
+        assertThat filterChainManager.getChain("/**"), contains(
+                instanceOf(DefaultFilter.invalidRequest.filterClass),
+                instanceOf(DefaultFilter.noAccess.filterClass))
         // configured routes also contain global filters
         assertThat filterChainManager.getChain("/login.html"), contains(
                 instanceOf(DefaultFilter.invalidRequest.filterClass),
diff --git 
a/support/spring/src/main/java/org/apache/shiro/spring/web/ShiroFilterFactoryBean.java
 
b/support/spring/src/main/java/org/apache/shiro/spring/web/ShiroFilterFactoryBean.java
index c65696927..a8e997522 100644
--- 
a/support/spring/src/main/java/org/apache/shiro/spring/web/ShiroFilterFactoryBean.java
+++ 
b/support/spring/src/main/java/org/apache/shiro/spring/web/ShiroFilterFactoryBean.java
@@ -135,6 +135,7 @@ public class ShiroFilterFactoryBean implements FactoryBean, 
BeanPostProcessor {
     private String loginUrl;
     private String successUrl;
     private String unauthorizedUrl;
+    private boolean allowAccessByDefault;
     private boolean caseInsensitive;
 
     private AbstractShiroFilter instance;
@@ -309,6 +310,22 @@ public class ShiroFilterFactoryBean implements 
FactoryBean, BeanPostProcessor {
         return filters;
     }
 
+    /**
+     * @return {@code true} if the default filter chain will allow access if 
no other filter chain matches.
+     */
+    public boolean isAllowAccessByDefault() {
+        return allowAccessByDefault;
+    }
+
+    /**
+     * Sets whether the default filter chain will allow access if no other 
filter chain matches.
+     *
+     * @param allowAccessByDefault {@code true} if the default filter chain 
will allow access
+     */
+    public void setAllowAccessByDefault(boolean allowAccessByDefault) {
+        this.allowAccessByDefault = allowAccessByDefault;
+    }
+
     /**
      * Sets the filterName-to-Filter map of filters available for reference 
when creating
      * {@link #setFilterChainDefinitionMap(java.util.Map) filter chain 
definitions}.
@@ -463,7 +480,11 @@ public class ShiroFilterFactoryBean implements 
FactoryBean, BeanPostProcessor {
 
         // create the default chain, to match anything the path matching would 
have missed
         // TODO this assumes ANT path matching, which might be OK here
-        manager.createDefaultChain("/**");
+        if (isAllowAccessByDefault()) {
+            manager.createDefaultChain("/**", DefaultFilter.anon.name());
+        } else {
+            manager.createDefaultChain("/**", DefaultFilter.noAccess.name());
+        }
 
         return manager;
     }
diff --git 
a/support/spring/src/test/java/org/apache/shiro/spring/web/ShiroFilterFactoryBeanTest.java
 
b/support/spring/src/test/java/org/apache/shiro/spring/web/ShiroFilterFactoryBeanTest.java
index 8956f2350..6b746e87b 100644
--- 
a/support/spring/src/test/java/org/apache/shiro/spring/web/ShiroFilterFactoryBeanTest.java
+++ 
b/support/spring/src/test/java/org/apache/shiro/spring/web/ShiroFilterFactoryBeanTest.java
@@ -19,7 +19,6 @@
 package org.apache.shiro.spring.web;
 
 import org.apache.shiro.web.filter.InvalidRequestFilter;
-import org.apache.shiro.web.filter.authc.FormAuthenticationFilter;
 import org.apache.shiro.web.filter.mgt.DefaultFilterChainManager;
 import org.apache.shiro.web.filter.mgt.NamedFilterList;
 import org.apache.shiro.web.filter.mgt.PathMatchingFilterChainResolver;
@@ -66,13 +65,12 @@ public class ShiroFilterFactoryBeanTest {
         DefaultFilterChainManager fcManager = (DefaultFilterChainManager) 
resolver.getFilterChainManager();
         NamedFilterList chain = fcManager.getChain("/test");
         assertThat(chain).isNotNull();
-        assertThat(chain).hasSize(3);
+        assertThat(chain).hasSize(2);
         Filter[] filters = new Filter[chain.size()];
         filters = chain.toArray(filters);
         // global filter
         assertThat(filters[0] instanceof InvalidRequestFilter).isTrue();
         assertThat(filters[1] instanceof DummyFilter).isTrue();
-        assertThat(filters[2] instanceof FormAuthenticationFilter).isTrue();
     }
 
     /**
@@ -93,7 +91,8 @@ public class ShiroFilterFactoryBeanTest {
         
expect(mockFilterConfig.getServletContext()).andReturn(mockServletContext).anyTimes();
         HttpServletRequest mockRequest = 
createNiceMock(HttpServletRequest.class);
         expect(mockRequest.getContextPath()).andReturn("/").anyTimes();
-        expect(mockRequest.getRequestURI()).andReturn("/").anyTimes();
+        expect(mockRequest.getRequestURI()).andReturn("/test").anyTimes();
+        expect(mockRequest.getServletPath()).andReturn("/test").anyTimes();
         HttpServletResponse mockResponse = 
createNiceMock(HttpServletResponse.class);
 
         replay(mockFilterConfig);
diff --git 
a/support/spring/src/test/resources/org/apache/shiro/spring/web/ShiroFilterFactoryBeanTest.xml
 
b/support/spring/src/test/resources/org/apache/shiro/spring/web/ShiroFilterFactoryBeanTest.xml
index 6403782e8..177784591 100644
--- 
a/support/spring/src/test/resources/org/apache/shiro/spring/web/ShiroFilterFactoryBeanTest.xml
+++ 
b/support/spring/src/test/resources/org/apache/shiro/spring/web/ShiroFilterFactoryBeanTest.xml
@@ -46,7 +46,7 @@
         <property name="securityManager" ref="securityManager"/>
         <property name="filterChainDefinitions">
             <value>
-                /test = testFilter, authc
+                /test = testFilter
             </value>
         </property>
 
diff --git 
a/web/src/main/java/org/apache/shiro/web/config/IniFilterChainResolverFactory.java
 
b/web/src/main/java/org/apache/shiro/web/config/IniFilterChainResolverFactory.java
index c4c9ea299..f5159eab2 100644
--- 
a/web/src/main/java/org/apache/shiro/web/config/IniFilterChainResolverFactory.java
+++ 
b/web/src/main/java/org/apache/shiro/web/config/IniFilterChainResolverFactory.java
@@ -61,6 +61,7 @@ public class IniFilterChainResolverFactory extends 
IniFactorySupport<FilterChain
 
     private List<String> globalFilters = 
Collections.singletonList(DefaultFilter.invalidRequest.name());
 
+    private boolean allowAccessByDefault;
     private boolean caseInsensitive = true;
 
     public IniFilterChainResolverFactory() {
@@ -92,6 +93,14 @@ public class IniFilterChainResolverFactory extends 
IniFactorySupport<FilterChain
         this.globalFilters = globalFilters;
     }
 
+    public boolean isAllowAccessByDefault() {
+        return allowAccessByDefault;
+    }
+
+    public void setAllowAccessByDefault(boolean allowAccessByDefault) {
+        this.allowAccessByDefault = allowAccessByDefault;
+    }
+
     public boolean isCaseInsensitive() {
         return caseInsensitive;
     }
@@ -158,7 +167,11 @@ public class IniFilterChainResolverFactory extends 
IniFactorySupport<FilterChain
 
         // create the default chain, to match anything the path matching would 
have missed
         // TODO this assumes ANT path matching
-        manager.createDefaultChain("/**");
+        if (isAllowAccessByDefault()) {
+            manager.createDefaultChain("/**", DefaultFilter.anon.name());
+        } else {
+            manager.createDefaultChain("/**", DefaultFilter.noAccess.name());
+        }
     }
 
     protected void registerFilters(Map<String, Filter> filters, 
FilterChainManager manager) {
diff --git 
a/web/src/main/java/org/apache/shiro/web/filter/authc/NoAccessFilter.java 
b/web/src/main/java/org/apache/shiro/web/filter/authc/NoAccessFilter.java
new file mode 100644
index 000000000..8d6e13afb
--- /dev/null
+++ b/web/src/main/java/org/apache/shiro/web/filter/authc/NoAccessFilter.java
@@ -0,0 +1,48 @@
+/*
+ * 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.filter.authc;
+
+import org.apache.shiro.authc.AuthenticationToken;
+import org.apache.shiro.web.util.WebUtils;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import jakarta.servlet.ServletRequest;
+import jakarta.servlet.ServletResponse;
+
+/**
+ * A request filter that redirects all traffic to a login page. This filter is 
used as a catch-all to block requests
+ * that do not match existing filter patterns.
+ */
+public class NoAccessFilter extends AuthenticatingFilter {
+
+    private final Logger log = LoggerFactory.getLogger(NoAccessFilter.class);
+
+    @Override
+    protected boolean onAccessDenied(ServletRequest request, ServletResponse 
response) throws Exception {
+        log.debug("Blocking access to request: '{}'", 
WebUtils.getPathWithinApplication(WebUtils.toHttp(request)));
+        saveRequestAndRedirectToLogin(request, response);
+        return false;
+    }
+
+    @Override
+    protected AuthenticationToken createToken(ServletRequest request, 
ServletResponse response) throws Exception {
+        return null;
+    }
+}
diff --git 
a/web/src/main/java/org/apache/shiro/web/filter/mgt/DefaultFilter.java 
b/web/src/main/java/org/apache/shiro/web/filter/mgt/DefaultFilter.java
index 267dbf863..2921bba2a 100644
--- a/web/src/main/java/org/apache/shiro/web/filter/mgt/DefaultFilter.java
+++ b/web/src/main/java/org/apache/shiro/web/filter/mgt/DefaultFilter.java
@@ -25,6 +25,7 @@ import 
org.apache.shiro.web.filter.authc.BasicHttpAuthenticationFilter;
 import org.apache.shiro.web.filter.authc.BearerHttpAuthenticationFilter;
 import org.apache.shiro.web.filter.authc.FormAuthenticationFilter;
 import org.apache.shiro.web.filter.authc.LogoutFilter;
+import org.apache.shiro.web.filter.authc.NoAccessFilter;
 import org.apache.shiro.web.filter.authc.UserFilter;
 import org.apache.shiro.web.filter.authz.HttpMethodPermissionFilter;
 import org.apache.shiro.web.filter.authz.IpFilter;
@@ -112,11 +113,14 @@ public enum DefaultFilter {
      * user filter.
      */
     user(UserFilter.class),
-
     /**
      * invalid request filter.
      */
-    invalidRequest(InvalidRequestFilter.class);
+    invalidRequest(InvalidRequestFilter.class),
+    /**
+     * no access filter.
+     */
+    noAccess(NoAccessFilter.class);
 
     private final Class<? extends Filter> filterClass;
 
diff --git 
a/web/src/main/java/org/apache/shiro/web/filter/mgt/DefaultFilterChainManager.java
 
b/web/src/main/java/org/apache/shiro/web/filter/mgt/DefaultFilterChainManager.java
index 6c9572f17..c7797eb88 100644
--- 
a/web/src/main/java/org/apache/shiro/web/filter/mgt/DefaultFilterChainManager.java
+++ 
b/web/src/main/java/org/apache/shiro/web/filter/mgt/DefaultFilterChainManager.java
@@ -136,12 +136,11 @@ public class DefaultFilterChainManager implements 
FilterChainManager {
         addFilter(name, filter, init, true);
     }
 
-    public void createDefaultChain(String chainName) {
+    public void createDefaultChain(String chainName, String chainDefinition) {
         // only create the defaultChain if we don't have a chain with this 
name already
         // (the global filters will already be in that chain)
-        if (!getChainNames().contains(chainName) && 
!CollectionUtils.isEmpty(globalFilterNames)) {
-            // add each of global filters
-            globalFilterNames.stream().forEach(filterName -> 
addToChain(chainName, filterName));
+        if (!getChainNames().contains(chainName)) {
+            createChain(chainName, chainDefinition);
         }
     }
 
diff --git 
a/web/src/main/java/org/apache/shiro/web/filter/mgt/FilterChainManager.java 
b/web/src/main/java/org/apache/shiro/web/filter/mgt/FilterChainManager.java
index dc573f439..5885a899b 100644
--- a/web/src/main/java/org/apache/shiro/web/filter/mgt/FilterChainManager.java
+++ b/web/src/main/java/org/apache/shiro/web/filter/mgt/FilterChainManager.java
@@ -168,13 +168,23 @@ public interface FilterChainManager {
 
     /**
      * Creates a chain that should match any non-matched request paths,
-     * typically {@code /**} assuming an {@link AntPathMatcher} I used.
+     * typically assuming an {@link AntPathMatcher} is used.
      *
      * @param chainName The name of the chain to create, likely {@code /**}.
      * @see AntPathMatcher AntPathMatcher
      * @since 1.6
      */
-    void createDefaultChain(String chainName);
+    void createDefaultChain(String chainName, String chainDefinition);
+
+    /**
+     * @since 1.6
+     * @deprecated use {@link FilterChainManager#createDefaultChain(String, 
String)} instead.
+     * @see AntPathMatcher AntPathMatcher
+     */
+    @Deprecated
+    default void createDefaultChain(String chainName) {
+        createDefaultChain(chainName, DefaultFilter.noAccess.name());
+    }
 
     /**
      * Adds (appends) a filter to the filter chain identified by the given 
{@code chainName}.  If there is no chain
diff --git 
a/web/src/test/groovy/org/apache/shiro/web/filter/mgt/DefaultFilterChainManagerTest.groovy
 
b/web/src/test/groovy/org/apache/shiro/web/filter/mgt/DefaultFilterChainManagerTest.groovy
index 6e2e55ee4..6d70e9583 100644
--- 
a/web/src/test/groovy/org/apache/shiro/web/filter/mgt/DefaultFilterChainManagerTest.groovy
+++ 
b/web/src/test/groovy/org/apache/shiro/web/filter/mgt/DefaultFilterChainManagerTest.groovy
@@ -232,11 +232,12 @@ class DefaultFilterChainManagerTest {
         // the  "default" chain doesn't exist until it is created
         assertThat(manager.getChain("/**"), Matchers.nullValue())
         // create it
-        manager.createDefaultChain("/**")
+        manager.createDefaultChain("/**", DefaultFilter.noAccess.name())
         // verify it
         assertThat(manager.getChain("/**"), Matchers.contains(
                 
Matchers.instanceOf(DefaultFilter.invalidRequest.getFilterClass()),
-                Matchers.instanceOf(DefaultFilter.port.getFilterClass())
+                Matchers.instanceOf(DefaultFilter.port.getFilterClass()),
+                Matchers.instanceOf(DefaultFilter.noAccess.getFilterClass())
         ))
     }
 
@@ -250,7 +251,7 @@ class DefaultFilterChainManagerTest {
         manager.createChain("test", "authc")
 
         // create the default chain with the same name
-        manager.createDefaultChain("test")
+        manager.createDefaultChain("test", DefaultFilter.noAccess.name())
 
         // since the "default" chain was created with the same name as an 
existing chain, we could end up adding the
         // global filters to the chain twice, test to verify it is only once

Reply via email to