I never received a reply to the below request.  Is it possible for
someone to review the CVE-2020-13933 patch?

Additionally, I have prepared two patches for CVE-2020-17510, which I
have attached to this email.  The adaptations were fairly minor, but a
review would still be appreciated.

As far as CVE-2020-17523, it looks the affected file
(support/spring-boot/spring-boot-web-starter/src/main/resources/META-INF/spring.factories)
was introduced in 1.4.x.  If that is the case, then CVE-2020-17523 would
not affect 1.3.x versions of shiro.  Do I have that right?

I'd like to get these changes wrapped up and a review would increase my
confidence in the adaptations I have made.

Once these are nailed down (fixes for CVE-2020-13933 and CVE-2020-17510,
and confirmation that CVE-2020-17523 is not applicable in 1.3.x), then I
will be in a position to address getting a more recent upstream release
into Debian.

Regards,

-Roberto

On Wed, Apr 07, 2021 at 03:41:25PM -0400, Roberto C. Sánchez wrote:
> Hi Brian, Ben, et al.,
> 
> I have what I believe to be a correct backport of commit dc194fc977ab to
> address CVE-2020-13933.  The adaptations/changes include:
> 
> - replacing the diamond operator <> with type specifications (the 1.3.x
>   build uses source compatibility level 1.6)
> - replacing stream constructs with loops
> - omitting changes to non-existent tests
> - adjusting for the absence of the FilterConfig type (which seems to
>   have been introduced in 1.4)
> 
> If someone familiar with the code, the vulnerability, and the fix could
> review the attached patch that would be very much appreciated.  Also, it
> would be quite helpful if there was a reproducer or a description of how
> to exploit the vulnerability to help with validating the fix.  If that
> cannot be disclosed, then perhaps someone could confirm that this patch
> does in fact address the vulnerability; that would be helpful.
> 
> Next I will start working on CVE-2020-17510 and CVE-2020-17523.  Once I
> have those sorted out for the existing 1.3.x packages I will turn my
> attention to seeing about updating to a newer upstream release (which
> could be a lengthy process).
> 
> Regards,
> 
> -Roberto
> 
> On Wed, Mar 31, 2021 at 03:21:55PM -0400, Roberto C. Sánchez wrote:
> > Hi Brian,
> > 
> > Thanks for your help.  I am working to backport dc194fc977ab to address
> > CVE-2020-13933 and after that I will move on to the fixes for
> > CVE-2020-17510 and CVE-2020-17523.
> > 
> > As far as the maintainability of a 1.3.x package, upgrading to a newer
> > version is not an option for two reasons.  First, I am working on
> > addressing these vulnerabilities in Debian Stretch, which is in the LTS
> > stage of its lifecycle, making an update to a new upstream release very
> > unlikely.  Second, the shiro package in Debian was last updated about 2
> > years ago and even in Debian unstable 1.3.x is the highest available
> > version.  Any update to a new upstream version would need to start in
> > the unstable distribution.
> > 
> > As an additional complication, the activemq package in Debian depends on
> > the shiro package, so a shiro update would need to be coordinated in a
> > that ensures it doesn't break activemq.
> > 
> > That said, I will bring the issue up to see if I can get an update
> > started so that at the least the next Debian stable release has
> > something more recent.
> > 
> > Regards,
> > 
> > -Roberto
> > 
> > On Tue, Mar 16, 2021 at 05:50:50PM -0400, Brian Demers wrote:
> > > Hey Roberto,
> > > 
> > > Sorry about the delay on this one, I originally thought we had answered
> > > your question.
> > > 
> > > The commit you are looking for is
> > > https://github.com/apache/shiro/commit/dc194fc977ab6cfbf3c1ecb085e2bac5db14af6d
> > > 
> > > If you are maintaining a 1.3.x package this is going to become more
> > > difficult, is it possible to deprecate it and move to a recent version?
> > > 
> > > 
> > > 
> > > On Sat, Jan 30, 2021 at 4:45 PM Roberto C. Sánchez <[email protected]>
> > > wrote:
> > > 
> > > > Bump.
> > > >
> > > > On Tue, Dec 22, 2020 at 09:30:47AM -0500, Roberto C. Sánchez wrote:
> > > > > On Mon, Dec 21, 2020 at 09:33:44PM +0100, Benjamin Marwell wrote:
> > > > > > Hi Roberto,
> > > > > >
> > > > > > after talking to the PMC chair, I can give you three commit links.
> > > > > >
> > > > > >
> > > > https://github.com/apache/shiro/commit/042c59356cc6442345a9f935aed3e7603cb4dfad
> > > > > >
> > > > https://github.com/apache/shiro/commit/5b1add9a4c4ed046b52cf2132ed0f264a22caf1d
> > > > > >
> > > > https://github.com/apache/shiro/commit/1b9d8d99cd6d50d7114916508a13677a0fe6f345
> > > > > >
> > > > > > I guess it is quite obvious what is inside these commits.
> > > > > >
> > > > > Hi Ben,
> > > > >
> > > > > This commits seem to have been made after the 1.6.0 release and before
> > > > > the 1.7.0 release.  My belief is that they address CVE-2020-17510.  
> > > > > Can
> > > > > you tell me if dc194fc977ab6cfbf3c1ecb085e2bac5db14af6d is the commit
> > > > > that addresses CVE-2020-13933?  Are there other commits that go along
> > > > > with it to completely remedy CVE-2020-13933?
> > > > >
> > > > > Regards,
> > > > >
> > > > > -Roberto
> > > > >
> > > > > --
> > > > > Roberto C. Sánchez
> > > >
> > > > --
> > > > Roberto C. Sánchez
> > > >
> > 
> > -- 
> > Roberto C. Sánchez
> > http://people.connexer.com/~roberto
> > http://www.connexer.com
> 
> -- 
> Roberto C. Sánchez
> http://people.connexer.com/~roberto
> http://www.connexer.com

> From dc194fc977ab6cfbf3c1ecb085e2bac5db14af6d Mon Sep 17 00:00:00 2001
> From: Brian Demers <[email protected]>
> Date: Tue, 7 Jul 2020 21:06:35 -0400
> Subject: [PATCH] Add a feature to allow for global filters
> 
> Adds new filter to block invalid requests
> ---
>  .../shiro/guice/web/ShiroWebModule.java       |  25 ++-
>  .../shiro/guice/web/ShiroWebModuleTest.java   | 153 ++++++++++++++++++
>  .../ShiroWebFilterConfiguration.java          |   8 +
>  .../web/ConfiguredGlobalFiltersTest.groovy    | 104 ++++++++++++
>  .../web/DisabledGlobalFiltersTest.groovy      |  64 ++++++++
>  ...ShiroWebSpringAutoConfigurationTest.groovy |  30 +++-
>  ...roWebAutoConfigurationTestApplication.java |   4 +-
>  .../spring/web/ShiroFilterFactoryBean.java    |  23 +++
>  .../config/AbstractShiroWebConfiguration.java |   3 -
>  .../AbstractShiroWebFilterConfiguration.java  |   9 +-
>  .../config/ShiroWebFilterConfiguration.java   |   6 +
>  .../ShiroWebFilterConfigurationTest.groovy    |   3 +-
>  .../web/ShiroFilterFactoryBeanTest.java       |   8 +-
>  .../config/IniFilterChainResolverFactory.java |  18 +++
>  .../web/filter/InvalidRequestFilter.java      | 124 ++++++++++++++
>  .../shiro/web/filter/mgt/DefaultFilter.java   |   4 +-
>  .../filter/mgt/DefaultFilterChainManager.java |  37 ++++-
>  .../web/filter/mgt/FilterChainManager.java    |  22 +++
>  .../web/servlet/AbstractShiroFilter.java      |   1 +
>  .../IniFilterChainResolverFactoryTest.groovy  |  26 +++
>  .../web/env/IniWebEnvironmentTest.groovy      |  69 ++++++++
>  .../filter/InvalidRequestFilterTest.groovy    | 106 ++++++++++++
>  .../mgt/DefaultFilterChainManagerTest.groovy  |  52 ++++++
>  .../org/apache/shiro/web/env/FilterStub.java  |  45 ++++++
>  24 files changed, 925 insertions(+), 19 deletions(-)
>  create mode 100644 
> support/spring-boot/spring-boot-web-starter/src/test/groovy/org/apache/shiro/spring/boot/autoconfigure/web/ConfiguredGlobalFiltersTest.groovy
>  create mode 100644 
> support/spring-boot/spring-boot-web-starter/src/test/groovy/org/apache/shiro/spring/boot/autoconfigure/web/DisabledGlobalFiltersTest.groovy
>  create mode 100644 
> web/src/main/java/org/apache/shiro/web/filter/InvalidRequestFilter.java
>  create mode 100644 
> web/src/test/groovy/org/apache/shiro/web/filter/InvalidRequestFilterTest.groovy
>  create mode 100644 web/src/test/java/org/apache/shiro/web/env/FilterStub.java
> 
> --- 
> 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
> @@ -18,9 +18,13 @@
>   */
>  package org.apache.shiro.guice.web;
>  
> +import java.util.ArrayList;
> +import java.util.Arrays;
>  import java.util.Collection;
> +import java.util.Collections;
>  import java.util.HashMap;
>  import java.util.LinkedHashMap;
> +import java.util.List;
>  import java.util.Map;
>  
>  import javax.servlet.Filter;
> @@ -32,6 +36,7 @@
>  import org.apache.shiro.mgt.SecurityManager;
>  import org.apache.shiro.session.mgt.SessionManager;
>  import org.apache.shiro.web.env.WebEnvironment;
> +import org.apache.shiro.web.filter.InvalidRequestFilter;;
>  import org.apache.shiro.web.filter.PathMatchingFilter;
>  import org.apache.shiro.web.filter.authc.AnonymousFilter;
>  import org.apache.shiro.web.filter.authc.BasicHttpAuthenticationFilter;
> @@ -86,7 +91,8 @@
>      public static final Key<SslFilter> SSL = Key.get(SslFilter.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);
>  
>      static final String NAME = "SHIRO";
>  
> @@ -123,6 +129,12 @@
>          };
>      }
>  
> +    public List<Key<? extends Filter>> globalFilters() {
> +        ArrayList<Key<? extends Filter>> filters = new ArrayList<Key<? 
> extends Filter>>();
> +        filters.add(INVALID_REQUEST);
> +        return Collections.unmodifiableList(filters);
> +    }
> +
>      @Override
>      protected final void configureShiro() {
>          bindBeanType(TypeLiteral.get(ServletContext.class), 
> Key.get(ServletContext.class, Names.named(NAME)));
> @@ -134,6 +146,12 @@
>  
>          this.configureShiroWeb();
>  
> +        // add default matching route if not already set
> +        if (!filterChains.containsKey("/**")) {
> +            // no config, this will add only the global filters
> +            this.addFilterChain("/**", new Key[0]);
> +        }
> +
>          setupFilterChainConfigs();
>  
>          bind(FilterChainResolver.class).toProvider(new 
> FilterChainResolverProvider(filterChains));
> @@ -143,8 +161,15 @@
>          Map<Key<? extends PathMatchingFilter>, Map<String, String>> configs 
> = new HashMap<Key<? extends PathMatchingFilter>, Map<String, String>>();
>  
>          for (Map.Entry<String, Key<? extends Filter>[]> filterChain : 
> filterChains.entrySet()) {
> -            for (int i = 0; i < filterChain.getValue().length; i++) {
> -                Key<? extends Filter> key = filterChain.getValue()[i];
> +            List<Key<? extends Filter>> globalFilters = this.globalFilters();
> +            Key<? extends Filter>[] pathFilters = filterChain.getValue();
> +
> +            // merge the global filters and the path specific filters
> +            List<Key<? extends Filter>> filterConfigs = new ArrayList<Key<? 
> extends Filter>>(globalFilters.size() + pathFilters.length);
> +            filterConfigs.addAll(globalFilters);
> +            filterConfigs.addAll(Arrays.asList(pathFilters));
> +            for (int i = 0; i < filterConfigs.size(); i++) {
> +                Key<? extends Filter> key = filterConfigs.get(i);
>                  if (key instanceof FilterConfigKey) {
>                      FilterConfigKey<? extends PathMatchingFilter> configKey 
> = (FilterConfigKey<? extends PathMatchingFilter>) key;
>                      key = configKey.getKey();
> --- 
> 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
> @@ -25,8 +25,10 @@
>  import org.apache.shiro.util.StringUtils;
>  import org.apache.shiro.web.config.IniFilterChainResolverFactory;
>  import org.apache.shiro.web.filter.AccessControlFilter;
> +import org.apache.shiro.web.filter.InvalidRequestFilter;
>  import org.apache.shiro.web.filter.authc.AuthenticationFilter;
>  import org.apache.shiro.web.filter.authz.AuthorizationFilter;
> +import org.apache.shiro.web.filter.mgt.DefaultFilter;
>  import org.apache.shiro.web.filter.mgt.DefaultFilterChainManager;
>  import org.apache.shiro.web.filter.mgt.FilterChainManager;
>  import org.apache.shiro.web.filter.mgt.FilterChainResolver;
> @@ -41,7 +43,9 @@
>  import org.springframework.beans.factory.config.BeanPostProcessor;
>  
>  import javax.servlet.Filter;
> +import java.util.ArrayList;
>  import java.util.LinkedHashMap;
> +import java.util.List;
>  import java.util.Map;
>  
>  /**
> @@ -121,6 +125,8 @@
>  
>      private Map<String, Filter> filters;
>  
> +    private List<String> globalFilters;
> +
>      private Map<String, String> filterChainDefinitionMap; 
> //urlPathExpression_to_comma-delimited-filter-chain-definition
>  
>      private String loginUrl;
> @@ -131,6 +137,8 @@
>  
>      public ShiroFilterFactoryBean() {
>          this.filters = new LinkedHashMap<String, Filter>();
> +        this.globalFilters = new ArrayList<String>();
> +        this.globalFilters.add(DefaultFilter.invalidRequest.name());
>          this.filterChainDefinitionMap = new LinkedHashMap<String, String>(); 
> //order matters!
>      }
>  
> @@ -332,6 +340,14 @@
>      }
>  
>      /**
> +     * Sets the list of filters that will be executed against every request. 
>  Defaults to the {@link InvalidRequestFilter} which will block known invalid 
> request attacks.
> +     * @param globalFilters the list of filters to execute before specific 
> path filters.
> +     */
> +    public void setGlobalFilters(List<String> globalFilters) {
> +        this.globalFilters = globalFilters;
> +    }
> +
> +    /**
>       * Lazily creates and returns a {@link AbstractShiroFilter} concrete 
> instance via the
>       * {@link #createInstance} method.
>       *
> @@ -388,6 +404,9 @@
>              }
>          }
>  
> +        // set the global filters
> +        manager.setGlobalFilters(this.globalFilters);
> +
>          //build up the chains:
>          Map<String, String> chains = getFilterChainDefinitionMap();
>          if (!CollectionUtils.isEmpty(chains)) {
> @@ -398,6 +417,9 @@
>              }
>          }
>  
> +        // create the default chain, to match anything the path matching 
> would have missed
> +        manager.createDefaultChain("/**"); // TODO this assumes ANT path 
> matching, which might be OK here
> +
>          return manager;
>      }
>  
> --- 
> a/web/src/main/java/org/apache/shiro/web/config/IniFilterChainResolverFactory.java
> +++ 
> b/web/src/main/java/org/apache/shiro/web/config/IniFilterChainResolverFactory.java
> @@ -24,6 +24,7 @@
>  import org.apache.shiro.config.ReflectionBuilder;
>  import org.apache.shiro.util.CollectionUtils;
>  import org.apache.shiro.util.Factory;
> +import org.apache.shiro.web.filter.mgt.DefaultFilter;
>  import org.apache.shiro.web.filter.mgt.FilterChainManager;
>  import org.apache.shiro.web.filter.mgt.FilterChainResolver;
>  import org.apache.shiro.web.filter.mgt.PathMatchingFilterChainResolver;
> @@ -32,7 +33,9 @@
>  
>  import javax.servlet.Filter;
>  import javax.servlet.FilterConfig;
> +import java.util.Collections;
>  import java.util.LinkedHashMap;
> +import java.util.List;
>  import java.util.Map;
>  
>  /**
> @@ -49,6 +52,8 @@
>  
>      private FilterConfig filterConfig;
>  
> +    private List<String> globalFilters = 
> Collections.singletonList(DefaultFilter.invalidRequest.name());
> +
>      private Map<String, ?> defaultBeans;
>  
>      public IniFilterChainResolverFactory() {
> @@ -72,6 +77,14 @@
>          this.filterConfig = filterConfig;
>      }
>  
> +    public List<String> getGlobalFilters() {
> +        return globalFilters;
> +    }
> +
> +    public void setGlobalFilters(List<String> globalFilters) {
> +        this.globalFilters = globalFilters;
> +    }
> +
>      protected FilterChainResolver createInstance(Ini ini) {
>          FilterChainResolver filterChainResolver = createDefaultInstance();
>          if (filterChainResolver instanceof PathMatchingFilterChainResolver) {
> @@ -122,9 +135,14 @@
>          //add the filters to the manager:
>          registerFilters(filters, manager);
>  
> +        manager.setGlobalFilters(getGlobalFilters());
> +
>          //urls section:
>          section = ini.getSection(URLS);
>          createChains(section, manager);
> +
> +        // create the default chain, to match anything the path matching 
> would have missed
> +        manager.createDefaultChain("/**"); // TODO this assumes ANT path 
> matching
>      }
>  
>      protected void registerFilters(Map<String, Filter> filters, 
> FilterChainManager manager) {
> --- /dev/null
> +++ b/web/src/main/java/org/apache/shiro/web/filter/InvalidRequestFilter.java
> @@ -0,0 +1,136 @@
> +/*
> + * 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;
> +
> +import org.apache.shiro.web.util.WebUtils;
> +
> +import javax.servlet.ServletRequest;
> +import javax.servlet.ServletResponse;
> +import java.util.Arrays;
> +import java.util.Collections;
> +import java.util.List;
> +
> +/**
> + * A request filter that blocks malicious requests. Invalid request will 
> respond with a 400 response code.
> + * <p>
> + * This filter checks and blocks the request if the following characters are 
> found in the request URI:
> + * <ul>
> + *     <li>Semicolon - can be disabled by setting {@code blockSemicolon = 
> false}</li>
> + *     <li>Backslash - can be disabled by setting {@code blockBackslash = 
> false}</li>
> + *     <li>Non-ASCII characters - can be disabled by setting {@code 
> blockNonAscii = false}, the ability to disable this check will be removed in 
> future version.</li>
> + * </ul>
> + *
> + * @see <a 
> href="https://docs.spring.io/spring-security/site/docs/current/api/org/springframework/security/web/firewall/StrictHttpFirewall.html";>This
>  class was inspired by Spring Security StrictHttpFirewall</a>
> + * @since 1.6
> + */
> +public class InvalidRequestFilter extends AccessControlFilter {
> +
> +    private static final List<String> SEMICOLON = 
> Collections.unmodifiableList(Arrays.asList(";", "%3b", "%3B"));
> +
> +    private static final List<String> BACKSLASH = 
> Collections.unmodifiableList(Arrays.asList("\\", "%5c", "%5C"));
> +
> +    private boolean blockSemicolon = true;
> +
> +    private boolean blockBackslash = true;
> +
> +    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);
> +    }
> +
> +    @Override
> +    protected boolean onAccessDenied(ServletRequest request, ServletResponse 
> response) throws Exception {
> +        WebUtils.toHttp(response).sendError(400, "Invalid request");
> +        return false;
> +    }
> +
> +    private boolean containsSemicolon(String uri) {
> +        if (isBlockSemicolon()) {
> +            int length = uri.length();
> +            for (int i = 0; i < length; i++) {
> +                char c = uri.charAt(i);
> +                if (c == ';') {
> +                    return true;
> +                }
> +            }
> +        }
> +        return false;
> +    }
> +
> +    private boolean containsBackslash(String uri) {
> +        if (isBlockBackslash()) {
> +            int length = uri.length();
> +            for (int i = 0; i < length; i++) {
> +                char c = uri.charAt(i);
> +                if (c == '\\') {
> +                    return true;
> +                }
> +            }
> +        }
> +        return false;
> +    }
> +
> +    private boolean containsNonAsciiCharacters(String uri) {
> +        if (isBlockNonAscii()) {
> +            return !containsOnlyPrintableAsciiCharacters(uri);
> +        }
> +        return false;
> +    }
> +
> +    private static boolean containsOnlyPrintableAsciiCharacters(String uri) {
> +        int length = uri.length();
> +        for (int i = 0; i < length; i++) {
> +            char c = uri.charAt(i);
> +            if (c < '\u0020' || c > '\u007e') {
> +                return false;
> +            }
> +        }
> +        return true;
> +    }
> +
> +    public boolean isBlockSemicolon() {
> +        return blockSemicolon;
> +    }
> +
> +    public void setBlockSemicolon(boolean blockSemicolon) {
> +        this.blockSemicolon = blockSemicolon;
> +    }
> +
> +    public boolean isBlockBackslash() {
> +        return blockBackslash;
> +    }
> +
> +    public void setBlockBackslash(boolean blockBackslash) {
> +        this.blockBackslash = blockBackslash;
> +    }
> +
> +    public boolean isBlockNonAscii() {
> +        return blockNonAscii;
> +    }
> +
> +    public void setBlockNonAscii(boolean blockNonAscii) {
> +        this.blockNonAscii = blockNonAscii;
> +    }
> +}
> --- 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
> @@ -19,6 +19,7 @@
>  package org.apache.shiro.web.filter.mgt;
>  
>  import org.apache.shiro.util.ClassUtils;
> +import org.apache.shiro.web.filter.InvalidRequestFilter;
>  import org.apache.shiro.web.filter.authc.*;
>  import org.apache.shiro.web.filter.authz.*;
>  import org.apache.shiro.web.filter.session.NoSessionCreationFilter;
> @@ -47,7 +48,8 @@
>      rest(HttpMethodPermissionFilter.class),
>      roles(RolesAuthorizationFilter.class),
>      ssl(SslFilter.class),
> -    user(UserFilter.class);
> +    user(UserFilter.class),
> +    invalidRequest(InvalidRequestFilter.class);
>  
>      private final Class<? extends Filter> filterClass;
>  
> --- 
> 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
> @@ -30,8 +30,10 @@
>  import javax.servlet.FilterChain;
>  import javax.servlet.FilterConfig;
>  import javax.servlet.ServletException;
> +import java.util.ArrayList;
>  import java.util.Collections;
>  import java.util.LinkedHashMap;
> +import java.util.List;
>  import java.util.Map;
>  import java.util.Set;
>  
> @@ -52,17 +54,21 @@
>  
>      private Map<String, Filter> filters; //pool of filters available for 
> creating chains
>  
> +    private List<String> globalFilterNames; // list of filters to prepend to 
> every chain
> +
>      private Map<String, NamedFilterList> filterChains; //key: chain name, 
> value: chain
>  
>      public DefaultFilterChainManager() {
>          this.filters = new LinkedHashMap<String, Filter>();
>          this.filterChains = new LinkedHashMap<String, NamedFilterList>();
> +        this.globalFilterNames = new ArrayList<String>();
>          addDefaultFilters(false);
>      }
>  
>      public DefaultFilterChainManager(FilterConfig filterConfig) {
>          this.filters = new LinkedHashMap<String, Filter>();
>          this.filterChains = new LinkedHashMap<String, NamedFilterList>();
> +        this.globalFilterNames = new ArrayList<String>();
>          setFilterConfig(filterConfig);
>          addDefaultFilters(true);
>      }
> @@ -115,6 +121,17 @@
>          addFilter(name, filter, init, true);
>      }
>  
> +    public void createDefaultChain(String chainName) {
> +        // 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
> +            for (String filterName : globalFilterNames) {
> +                addToChain(chainName, filterName);
> +            }
> +        }
> +    }
> +
>      public void createChain(String chainName, String chainDefinition) {
>          if (!StringUtils.hasText(chainName)) {
>              throw new NullPointerException("chainName cannot be null or 
> empty.");
> @@ -124,7 +141,14 @@
>          }
>  
>          if (log.isDebugEnabled()) {
> -            log.debug("Creating chain [" + chainName + "] from String 
> definition [" + chainDefinition + "]");
> +            log.debug("Creating chain [" + chainName + "] with global 
> filters " + globalFilterNames + " and from String definition [" + 
> chainDefinition + "]");
> +        }
> +
> +        // first add each of global filters
> +        if (!CollectionUtils.isEmpty(globalFilterNames)) {
> +            for (String filterName : globalFilterNames) {
> +                addToChain(chainName, filterName);
> +            }
>          }
>  
>          //parse the value by tokenizing it to get the resulting 
> filter-specific config entries
> @@ -273,6 +297,21 @@
>          chain.add(filter);
>      }
>  
> +    public void setGlobalFilters(List<String> globalFilterNames) throws 
> ConfigurationException {
> +        // validate each filter name
> +        if (!CollectionUtils.isEmpty(globalFilterNames)) {
> +            for (String filterName : globalFilterNames) {
> +                Filter filter = filters.get(filterName);
> +                if (filter == null) {
> +                    throw new ConfigurationException("There is no filter 
> with name '" + filterName +
> +                                                     "' to apply to the 
> global filters in the pool of available Filters.  Ensure a " +
> +                                                     "filter with that 
> name/path has first been registered with the addFilter method(s).");
> +                }
> +                this.globalFilterNames.add(filterName);
> +            }
> +        }
> +    }
> +
>      protected void applyChainConfig(String chainName, Filter filter, String 
> chainSpecificFilterConfig) {
>          if (log.isDebugEnabled()) {
>              log.debug("Attempting to apply path [" + chainName + "] to 
> filter [" + filter + "] " +
> --- 
> 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
> @@ -22,6 +22,7 @@
>  
>  import javax.servlet.Filter;
>  import javax.servlet.FilterChain;
> +import java.util.List;
>  import java.util.Map;
>  import java.util.Set;
>  
> @@ -165,6 +166,14 @@
>      void createChain(String chainName, String chainDefinition);
>  
>      /**
> +     * Creates a chain that should match any non-matched request paths, 
> typically {@code /**} assuming an {@link AntPathMatcher} I used.
> +     * @param chainName The name of the chain to create, likely {@code /**}.
> +     * @since 1.6
> +     * @see org.apache.shiro.lang.util.AntPathMatcher AntPathMatcher
> +     */
> +    void createDefaultChain(String chainName);
> +
> +    /**
>       * Adds (appends) a filter to the filter chain identified by the given 
> {@code chainName}.  If there is no chain
>       * with the given name, a new one is created and the filter will be the 
> first in the chain.
>       *
> @@ -195,4 +204,17 @@
>       *                                  interface).
>       */
>      void addToChain(String chainName, String filterName, String 
> chainSpecificFilterConfig) throws ConfigurationException;
> +
> +    /**
> +     * Configures the set of named filters that will match all paths.  These 
> filters will match BEFORE explicitly
> +     * configured filter chains i.e. by calling {@link #createChain(String, 
> String)}, {@link #addToChain(String, String)}, etc.
> +     * <br>
> +     * <strong>Filters configured in this list wll apply to ALL 
> requests.</strong>
> +     *
> +     * @param globalFilterNames         the list of filter names to match 
> ALL paths.
> +     * @throws ConfigurationException   if one of the filter names is 
> invalid and cannot be loaded from the set of
> +     *                                  configured filters {@link 
> #getFilters()}}.
> +     * @since 1.6
> +     */
> +    void setGlobalFilters(List<String> globalFilterNames) throws 
> ConfigurationException;
>  }


-- 
Roberto C. Sánchez
http://people.connexer.com/~roberto
http://www.connexer.com

Reply via email to