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