[Date Prev][Date Next] [Thread Prev][Thread Next] [Date Index] [Thread Index]

Bug#993134: marked as done (buster-pu: package shiro/1.3.2-4+deb10u1)



Your message dated Sat, 09 Oct 2021 12:11:43 +0100
with message-id <896b7609401ceb0e1c537222e26587ea2351415d.camel@adam-barratt.org.uk>
and subject line Closing bugs for fixes included in the 10.11 point release
has caused the Debian Bug report #993134,
regarding buster-pu: package shiro/1.3.2-4+deb10u1
to be marked as done.

This means that you claim that the problem has been dealt with.
If this is not the case it is now your responsibility to reopen the
Bug report if necessary, and/or fix the problem forthwith.

(NB: If you are a system administrator and have no idea what this
message is talking about, this may indicate a serious mail system
misconfiguration somewhere. Please contact owner@bugs.debian.org
immediately.)


-- 
993134: https://bugs.debian.org/cgi-bin/bugreport.cgi?bug=993134
Debian Bug Tracking System
Contact owner@bugs.debian.org with problems
--- Begin Message ---
Package: release.debian.org
Severity: normal
Tags: buster
User: release.debian.org@packages.debian.org
Usertags: pu

-----BEGIN PGP SIGNED MESSAGE-----
Hash: SHA512

I have prepared an update for shiro in buster.  This has been
coordinated with the package maintainer and at the recommendation of the
security team and with their concurrence, it is being proposed for the
next buster point release.

Please find attached the source debdiff.

Regards,

- -Roberto

-----BEGIN PGP SIGNATURE-----

iQIzBAEBCgAdFiEEz9ERzDttUsU/BH8iLNd4Xt2nsg8FAmEpJM0ACgkQLNd4Xt2n
sg+AxBAAhQYzOuX+czrEryQMv/mGTpyPyCQ3jeJJOToOnlr8lZRRbMSqlb8K5/nu
4R1ruPiJxTaRwc3mDCRYOCGGagGRZeSu3+ZGs7HjYogr0ifZiOq6Q3t6Vr0QC8Zt
ySFgTN8B+3ReOqjtERRpp/uVy4P91vD28DU/YfP2hCDRrjiqjb4bbg0vd/FM2Tjj
G3/wmF1qn76uXCZwEV0THMexxV5LQ1RAkIvMLn09XBYi8ASIUDyHA2YRGHj1pWzx
eZUy0miDa5GWE7FSXJ3CSDTIKB4DG7/jtX+fREZsItlaw4Ldk2QMkoMC71Lj/flk
2M31LrE4jQVT9tpesHmcBx/nx9zxJLKdDohQclZNc2r84CXdM7qgQbjrDIo3snAr
NSvMPVpa8jaWe4bu1U3jXMQ9Jqo6PYacCGbAV84rzhmVKIXkKc2OLd+rbVDs1cOE
1I3zQE2q1Ai+KodrjCu53sptTo8VdXOJzC56a1F3lRTtLPtcw0KX32nUxDPuLXnh
xNwBF1ikP3f9sX4CTAPmuqfLqPwxq2PFN/yDvtrilgTbn/g7cN0k2/RthNJ3uCQF
Pn5QNOB0r3GBjvgoiuwzSacgu869lZq9o1J+TtGL6bwyKgZQajkipft/DFYxwzJY
PzUh+qwitqgtlp3Vt/q58X31joLAKE1ZxgdCAc/EZ8Q87m7SV8w=
=2CUL
-----END PGP SIGNATURE-----
diff -Nru shiro-1.3.2/debian/changelog shiro-1.3.2/debian/changelog
--- shiro-1.3.2/debian/changelog	2019-03-01 16:36:03.000000000 -0500
+++ shiro-1.3.2/debian/changelog	2021-08-06 14:25:38.000000000 -0400
@@ -1,3 +1,20 @@
+shiro (1.3.2-4+deb10u1) buster; urgency=medium
+
+  * Non-maintainer upload by the Security Team.
+  * Update patch for Spring Framework 4.3.x build failure.
+  * Cherry-pick upstream patch with Guice improvements.
+  * CVE-2020-1957: Fix a path-traversal issue where a specially-crafted request
+    could cause an authentication bypass. (Closes: #955018)
+  * CVE-2020-11989: Fix an encoding issue introduced in the handling of the
+    previous CVE-2020-1957 path-traversal issue which could have also caused an
+    authentication bypass.
+  * CVE-2020-13933: Fix an authentication bypass resulting from a specially
+    crafted HTTP request. (Closes: #968753)
+  * CVE-2020-17510: Fix an authentication bypass resulting from a specially
+    crafted HTTP request.
+
+ -- Roberto C. Sánchez <roberto@debian.org>  Fri, 06 Aug 2021 14:25:38 -0400
+
 shiro (1.3.2-4) unstable; urgency=medium
 
   * Team upload.
diff -Nru shiro-1.3.2/debian/patches/03-spring-compatibility.patch shiro-1.3.2/debian/patches/03-spring-compatibility.patch
--- shiro-1.3.2/debian/patches/03-spring-compatibility.patch	2019-03-01 16:36:03.000000000 -0500
+++ shiro-1.3.2/debian/patches/03-spring-compatibility.patch	2021-08-06 14:25:38.000000000 -0400
@@ -1,17 +1,33 @@
-Description: Fixes the compatibility with the version of Spring Framework in Debian
-Author: Emmanuel Bourg <ebourg@apache.org>
-Forwarded: no
+From aa2cd4fca10416623ecc29008cd851a4f1ed3d98 Mon Sep 17 00:00:00 2001
+From: Brian Demers <bdemers@apache.org>
+Date: Fri, 23 Sep 2016 16:43:48 -0400
+Subject: [PATCH] SHIRO-590 - Added Spring Boot starters and programatic Spring
+ support.
+
+---
+ .../shiro/spring/LifecycleBeanPostProcessor.java      | 11 +++++++++++
+ 1 file changed, 11 insertions(+)
+
+diff --git a/support/spring/src/main/java/org/apache/shiro/spring/LifecycleBeanPostProcessor.java b/support/spring/src/main/java/org/apache/shiro/spring/LifecycleBeanPostProcessor.java
+index a526769e..a318d20b 100644
 --- a/support/spring/src/main/java/org/apache/shiro/spring/LifecycleBeanPostProcessor.java
 +++ b/support/spring/src/main/java/org/apache/shiro/spring/LifecycleBeanPostProcessor.java
-@@ -125,6 +125,11 @@
-         }
+@@ -134,4 +134,15 @@ public int getOrder() {
+         // LifecycleBeanPostProcessor needs Order. See https://issues.apache.org/jira/browse/SHIRO-222
+         return order;
      }
- 
-+    @Override
-+    public boolean requiresDestruction(Object object) {
-+        return true;
-+    }
 +
-     /**
-      * Order value of this BeanPostProcessor.
-      *
++    /**
++     * Return true only if <code>bean</code> implements Destroyable.
++     * @param bean bean to check if requires destruction.
++     * @return true only if <code>bean</code> implements Destroyable.
++     * @since 1.4
++     */
++    @SuppressWarnings("unused")
++    public boolean requiresDestruction(Object bean) {
++        return (bean instanceof Destroyable);
++    }
+ }
+-- 
+2.20.1
+
diff -Nru shiro-1.3.2/debian/patches/05-guice-improvements.patch shiro-1.3.2/debian/patches/05-guice-improvements.patch
--- shiro-1.3.2/debian/patches/05-guice-improvements.patch	1969-12-31 19:00:00.000000000 -0500
+++ shiro-1.3.2/debian/patches/05-guice-improvements.patch	2021-08-06 14:25:38.000000000 -0400
@@ -0,0 +1,751 @@
+commit f2dfa7ff39c9870e7b9856ceca8690c5398080fa
+Author: Brian Demers <bdemers@apache.org>
+Date:   Thu Jul 14 09:51:45 2016 -0400
+
+    SHIRO-493 - Adding new methods and deprecating old to ShiroWebModule to support Guice 4
+
+--- a/support/guice/src/main/java/org/apache/shiro/guice/ShiroModule.java
++++ b/support/guice/src/main/java/org/apache/shiro/guice/ShiroModule.java
+@@ -18,20 +18,33 @@
+  */
+ package org.apache.shiro.guice;
+ 
++import java.lang.reflect.Method;
+ import java.util.Collection;
+ import java.util.Collections;
++import java.util.List;
+ import java.util.Set;
+ import java.util.WeakHashMap;
+ 
+ import javax.annotation.PreDestroy;
+ 
++import com.google.inject.Provider;
++import com.google.inject.matcher.Matchers;
++import com.google.inject.name.Names;
++import com.google.inject.spi.InjectionListener;
++import com.google.inject.spi.TypeEncounter;
++import com.google.inject.spi.TypeListener;
+ import org.apache.shiro.config.ConfigurationException;
+ import org.apache.shiro.env.Environment;
++import org.apache.shiro.event.EventBus;
++import org.apache.shiro.event.EventBusAware;
++import org.apache.shiro.event.Subscribe;
++import org.apache.shiro.event.support.DefaultEventBus;
+ import org.apache.shiro.mgt.DefaultSecurityManager;
+ import org.apache.shiro.mgt.SecurityManager;
+ import org.apache.shiro.realm.Realm;
+ import org.apache.shiro.session.mgt.DefaultSessionManager;
+ import org.apache.shiro.session.mgt.SessionManager;
++import org.apache.shiro.util.ClassUtils;
+ import org.apache.shiro.util.Destroyable;
+ 
+ import com.google.inject.Key;
+@@ -57,6 +70,9 @@
+         bindSessionManager(bind(SessionManager.class));
+         bindEnvironment(bind(Environment.class));
+         bindListener(BeanTypeListener.MATCHER, new BeanTypeListener());
++        bindEventBus(bind(EventBus.class));
++        bindListener(Matchers.any(), new SubscribedEventTypeListener());
++        bindListener(Matchers.any(), new EventBusAwareTypeListener());
+         final DestroyableInjectionListener.DestroyableRegistry registry = new DestroyableInjectionListener.DestroyableRegistry() {
+             public void add(Destroyable destroyable) {
+                 ShiroModule.this.add(destroyable);
+@@ -70,6 +86,7 @@
+         bindListener(LifecycleTypeListener.MATCHER, new LifecycleTypeListener(registry));
+ 
+         expose(SecurityManager.class);
++        expose(EventBus.class);
+ 
+         configureShiro();
+         bind(realmCollectionKey())
+@@ -153,6 +170,15 @@
+     }
+ 
+     /**
++     * Binds the EventBus.  Override this method in order to provide your own {@link EventBus} binding.
++     * @param bind
++     * @since 1.4
++     */
++    protected void bindEventBus(AnnotatedBindingBuilder<EventBus> bind) {
++        bind.to(DefaultEventBus.class).asEagerSingleton();
++    }
++
++    /**
+      * Destroys all beans created within this module that implement {@link org.apache.shiro.util.Destroyable}.  Should be called when this
+      * module will no longer be used.
+      *
+@@ -167,4 +193,39 @@
+     public void add(Destroyable destroyable) {
+         this.destroyables.add(destroyable);
+     }
++
++    private class SubscribedEventTypeListener implements TypeListener {
++        @Override
++        public <I> void hear(TypeLiteral<I> typeLiteral, TypeEncounter<I> typeEncounter) {
++
++            final Provider<EventBus> eventBusProvider = typeEncounter.getProvider(EventBus.class);
++
++            List<Method> methods = ClassUtils.getAnnotatedMethods(typeLiteral.getRawType(), Subscribe.class);
++            if (methods != null && !methods.isEmpty()) {
++                typeEncounter.register( new InjectionListener<I>() {
++                    @Override
++                    public void afterInjection(Object o) {
++                        eventBusProvider.get().register(o);
++                    }
++                });
++            }
++        }
++    }
++
++    private class EventBusAwareTypeListener implements TypeListener {
++        @Override
++        public <I> void hear(TypeLiteral<I> typeLiteral, TypeEncounter<I> typeEncounter) {
++
++            final Provider<EventBus> eventBusProvider = typeEncounter.getProvider(EventBus.class);
++
++            if (EventBusAware.class.isAssignableFrom(typeLiteral.getRawType())) {
++                typeEncounter.register( new InjectionListener<I>() {
++                    @Override
++                    public void afterInjection(Object o) {
++                        ((EventBusAware)o).setEventBus(eventBusProvider.get());
++                    }
++                });
++            }
++        }
++    }
+ }
+--- 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,10 +18,7 @@
+  */
+ package org.apache.shiro.guice.web;
+ 
+-import java.util.Collection;
+-import java.util.HashMap;
+-import java.util.LinkedHashMap;
+-import java.util.Map;
++import java.util.*;
+ 
+ import javax.servlet.Filter;
+ import javax.servlet.ServletContext;
+@@ -31,6 +28,7 @@
+ import org.apache.shiro.guice.ShiroModule;
+ import org.apache.shiro.mgt.SecurityManager;
+ import org.apache.shiro.session.mgt.SessionManager;
++import org.apache.shiro.util.StringUtils;
+ import org.apache.shiro.web.env.WebEnvironment;
+ import org.apache.shiro.web.filter.PathMatchingFilter;
+ import org.apache.shiro.web.filter.authc.AnonymousFilter;
+@@ -94,7 +92,7 @@
+      * We use a LinkedHashMap here to ensure that iterator order is the same as add order.  This is important, as the
+      * FilterChainResolver uses iterator order when searching for a matching chain.
+      */
+-    private final Map<String, Key<? extends Filter>[]> filterChains = new LinkedHashMap<String, Key<? extends Filter>[]>();
++    private final Map<String, FilterConfig<? extends Filter>[]> filterChains = new LinkedHashMap<String, FilterConfig<? extends Filter>[]>();
+     private final ServletContext servletContext;
+ 
+     public ShiroWebModule(ServletContext servletContext) {
+@@ -134,37 +132,65 @@
+ 
+         this.configureShiroWeb();
+ 
+-        setupFilterChainConfigs();
+-
+-        bind(FilterChainResolver.class).toProvider(new FilterChainResolverProvider(filterChains));
++        bind(FilterChainResolver.class).toProvider(new FilterChainResolverProvider(setupFilterChainConfigs()));
+     }
+ 
+-    private void setupFilterChainConfigs() {
+-        Map<Key<? extends PathMatchingFilter>, Map<String, String>> configs = new HashMap<Key<? extends PathMatchingFilter>, Map<String, String>>();
++    private Map<String, Key<? extends Filter>[]> setupFilterChainConfigs() {
++
++        // loop through and build a map of Filter Key -> Map<Path, Config>
++        Map<Key<? extends Filter>, Map<String, String>> filterToPathToConfig = new HashMap<Key<? extends Filter>, Map<String, String>>();
++
++        // At the same time build a map to return with Path -> Key[]
++        Map<String, Key<? extends Filter>[]> resultConfigMap = new HashMap<String, Key<? extends Filter>[]>();
++
++        for (Map.Entry<String, FilterConfig<? extends Filter>[]> filterChain : filterChains.entrySet()) {
++
++            String path = filterChain.getKey();
++
++            // collect the keys used for this path
++            List<Key<? extends Filter>> keysForPath = new ArrayList<Key<? extends Filter>>();
+ 
+-        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];
+-                if (key instanceof FilterConfigKey) {
+-                    FilterConfigKey<? extends PathMatchingFilter> configKey = (FilterConfigKey<? extends PathMatchingFilter>) key;
+-                    key = configKey.getKey();
+-                    filterChain.getValue()[i] = key;
+-                    if (!PathMatchingFilter.class.isAssignableFrom(key.getTypeLiteral().getRawType())) {
+-                        throw new ConfigurationException("Config information requires a PathMatchingFilter - can't apply to " + key.getTypeLiteral().getRawType());
+-                    }
+-                    if (configs.get(castToPathMatching(key)) == null) configs.put(castToPathMatching(key), new HashMap<String, String>());
+-                    configs.get(castToPathMatching(key)).put(filterChain.getKey(), configKey.getConfigValue());
+-                } else if (PathMatchingFilter.class.isAssignableFrom(key.getTypeLiteral().getRawType())) {
+-	                  if (configs.get(castToPathMatching(key)) == null) configs.put(castToPathMatching(key), new HashMap<String, String>());
+-                    configs.get(castToPathMatching(key)).put(filterChain.getKey(), "");
++                FilterConfig<? extends Filter> filterConfig = filterChain.getValue()[i];
++
++                Key<? extends Filter> key = filterConfig.getKey();
++                String config = filterConfig.getConfigValue();
++
++                // initialize key in filterToPathToConfig, if it doesn't exist
++                if (filterToPathToConfig.get(key) == null) {
++                    filterToPathToConfig.put((key), new HashMap<String, String>());
++                }
++                // now set the value
++                filterToPathToConfig.get(key).put(path, config);
++
++                // Config error if someone configured a non PathMatchingFilter with a config value
++                if (StringUtils.hasText(config) && !PathMatchingFilter.class.isAssignableFrom(key.getTypeLiteral().getRawType())) {
++                    throw new ConfigurationException("Config information requires a PathMatchingFilter - can't apply to " + key.getTypeLiteral().getRawType());
+                 }
++
++                // store the key in keysForPath
++                keysForPath.add(key);
+             }
++
++            // map the current path to all of its Keys
++            resultConfigMap.put(path, keysForPath.toArray(new Key[keysForPath.size()]));
+         }
+-        for (Key<? extends PathMatchingFilter> filterKey : configs.keySet()) {
+-            bindPathMatchingFilter(filterKey, configs.get(filterKey));
++
++        // now we find only the PathMatchingFilter and configure bindings
++        // non PathMatchingFilter, can be loaded with the default provider via the class name
++        for (Key<? extends Filter> key : filterToPathToConfig.keySet()) {
++            if (PathMatchingFilter.class.isAssignableFrom(key.getTypeLiteral().getRawType())) {
++                bindPathMatchingFilter(castToPathMatching(key), filterToPathToConfig.get(key));
++            }
++            else {
++                bind(key);
++            }
+         }
++
++        return resultConfigMap;
+     }
+ 
++
+     private <T extends PathMatchingFilter> void bindPathMatchingFilter(Key<T> filterKey, Map<String, String> configs) {
+         bind(filterKey).toProvider(new PathMatchingFilterProvider<T>(filterKey, configs)).asEagerSingleton();
+     }
+@@ -218,6 +244,126 @@
+         bind.to(WebGuiceEnvironment.class).asEagerSingleton();
+     }
+ 
++    protected final void addFilterChain(String pattern, Key<? extends Filter> key) {
++        // check for legacy API
++        if (key instanceof FilterConfigKey) {
++            addLegacyFilterChain(pattern, (FilterConfigKey) key);
++        }
++        else {
++            addFilterChain(pattern, new FilterConfig<Filter>((Key<Filter>) key, ""));
++        }
++    }
++
++    /**
++     * Maps 'n' number of <code>filterConfig</code>s to a specific path pattern.<BR/>
++     * For example, a path of '/my_private_resource/**' to 'filterConfig(AUTHC)' would require
++     * any resource under the path '/my_private_resource' would be processed through the {@link FormAuthenticationFilter}.
++     *
++     * @param pattern URL patter to be mapped to a FilterConfig, e.g. '/my_private-path/**'
++     * @param filterConfigs FilterConfiguration representing the Filter and config to be used when processing resources on <code>pattern</code>.
++     * @since 1.4
++     */
++    protected final void addFilterChain(String pattern, FilterConfig<? extends Filter>... filterConfigs) {
++        filterChains.put(pattern, filterConfigs);
++    }
++
++    /**
++     * Builds a FilterConfig from a Filer and configuration String
++     * @param baseKey The Key of the Filter class to be used.
++     * @param <T> A Servlet Filter class.
++     * @return A FilterConfig used to map a String path to this configuration.
++     * @since 1.4
++     */
++    protected static <T extends Filter> FilterConfig<T> filterConfig(Key<T> baseKey, String configValue) {
++        return new FilterConfig<T>(baseKey, configValue);
++    }
++
++    /**
++     * Builds a FilterConfig from a Filer and configuration String
++     * @param baseKey The Key of the Filter class to be used.
++     * @param <T> A Servlet Filter class.
++     * @return A FilterConfig used to map a String path to this configuration.
++     * @since 1.4
++     */
++    protected static <T extends Filter> FilterConfig<T> filterConfig(Key<T> baseKey) {
++        return filterConfig(baseKey, "");
++    }
++
++    /**
++     * Builds a FilterConfig from a Filer and configuration String
++     * @param typeLiteral The TyleLiteral of the filter key to be used.
++     * @param configValue the configuration used.
++     * @param <T> A Servlet Filter class.
++     * @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(TypeLiteral<T> typeLiteral, String configValue) {
++        return filterConfig(Key.get(typeLiteral), configValue);
++    }
++
++    /**
++     * Builds a FilterConfig from a Filer and configuration String
++     * @param type The filter to be used.
++     * @param configValue the configuration used.
++     * @param <T> A Servlet Filter class.
++     * @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);
++    }
++
++
++    /**
++     * Filter configuration which pairs a Filter class with its configuration used on a path.
++     * @param <T> The Servlet Filter class.
++     * @since 1.4
++     */
++    public static class FilterConfig<T extends Filter> {
++        private Key<T> key;
++        private String configValue;
++
++        private FilterConfig(Key<T> key, String configValue) {
++            super();
++            this.key = key;
++            this.configValue = configValue;
++        }
++
++        public Key<T> getKey() {
++            return key;
++        }
++
++        public String getConfigValue() {
++            return configValue;
++        }
++    }
++
++
++
++
++
++
++
++    // legacy methods
++
++
++    static boolean isGuiceVersion3() {
++        try {
++            Class.forName("com.google.inject.multibindings.MapKey");
++            return false;
++        } catch (ClassNotFoundException e) {
++            return true;
++        }
++    }
++
++    private void addLegacyFilterChain(String pattern, FilterConfigKey filterConfigKey) {
++
++        FilterConfig<Filter> filterConfig = new FilterConfig<Filter>(filterConfigKey.getKey(), filterConfigKey.getConfigValue());
++        addFilterChain(pattern, filterConfig);
++    }
++
+     /**
+      * Adds a filter chain to the shiro configuration.
+      * <p/>
+@@ -228,24 +374,52 @@
+      * @param keys
+      */
+     @SuppressWarnings({"UnusedDeclaration"})
++    @Deprecated
+     protected final void addFilterChain(String pattern, Key<? extends Filter>... keys) {
+-        filterChains.put(pattern, keys);
++
++        // We need to extract the keys and FilterConfigKey and convert to the new format.
++
++        FilterConfig[] filterConfigs = new FilterConfig[keys.length];
++        for (int ii = 0; ii < keys.length; ii++) {
++            Key<? extends Filter> key = keys[ii];
++            // If this is a path matching filter, we need to remember the config
++            if (key instanceof FilterConfigKey) {
++                // legacy config
++                FilterConfigKey legacyKey = (FilterConfigKey) key;
++                filterConfigs[ii] = new FilterConfig(legacyKey.getKey(), legacyKey.getConfigValue());
++            }
++            else {
++                // Some other type of Filter key, no config
++                filterConfigs[ii] = new FilterConfig(key, "");
++            }
++        }
++
++        filterChains.put(pattern, filterConfigs);
+     }
+ 
++    @Deprecated
+     protected static <T extends PathMatchingFilter> Key<T> config(Key<T> baseKey, String configValue) {
++
++        if( !isGuiceVersion3()) {
++            throw new ConfigurationException("Method ShiroWebModule.config(Key<? extends PathMatchingFilter>, String configValue), is not supported when using Guice 4+");
++        }
++
+         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);
+     }
+ 
++    @Deprecated
+     private static class FilterConfigKey<T extends PathMatchingFilter> extends Key<T> {
+         private Key<T> key;
+         private String configValue;
+@@ -264,4 +438,5 @@
+             return configValue;
+         }
+     }
++
+ }
+--- a/support/guice/src/main/java/org/apache/shiro/guice/web/SimpleFilterChain.java
++++ b/support/guice/src/main/java/org/apache/shiro/guice/web/SimpleFilterChain.java
+@@ -44,4 +44,13 @@
+             originalChain.doFilter(request, response);
+         }
+     }
++
++    /**
++     * Exposed for testing, not part of public API.
++     * @return an Iterater of filters.
++     */
++    Iterator<? extends Filter> getFilters() {
++        return chain;
++    }
++
+ }
+--- a/support/guice/src/test/java/org/apache/shiro/guice/ShiroModuleTest.java
++++ b/support/guice/src/test/java/org/apache/shiro/guice/ShiroModuleTest.java
+@@ -28,6 +28,10 @@
+ import org.apache.shiro.authc.AuthenticationToken;
+ import org.apache.shiro.authc.SimpleAuthenticationInfo;
+ import org.apache.shiro.env.Environment;
++import org.apache.shiro.event.EventBus;
++import org.apache.shiro.event.EventBusAware;
++import org.apache.shiro.event.Subscribe;
++import org.apache.shiro.event.support.DefaultEventBus;
+ import org.apache.shiro.mgt.DefaultSecurityManager;
+ import org.apache.shiro.mgt.SecurityManager;
+ import org.apache.shiro.realm.Realm;
+@@ -37,11 +41,13 @@
+ import org.apache.shiro.util.Destroyable;
+ import org.junit.Test;
+ 
++import java.lang.reflect.Field;
+ import java.util.Collection;
++import java.util.Map;
+ 
+ import static org.easymock.EasyMock.*;
+-import static org.junit.Assert.assertNotNull;
+-import static org.junit.Assert.assertTrue;
++import static org.junit.Assert.*;
++import static org.hamcrest.CoreMatchers.*;
+ 
+ public class ShiroModuleTest {
+ 
+@@ -204,6 +210,82 @@
+         verify(myDestroyable);
+     }
+ 
++    /**
++     * @since 1.4
++     * @throws Exception
++     */
++    @Test
++    public void testEventListener() throws Exception {
++
++        final MockRealm mockRealm = createMock(MockRealm.class);
++        final EventBus eventBus = createMock(EventBus.class);
++
++        // expect both objects to be registered
++        eventBus.register(anyObject(MockEventListener1.class));
++        eventBus.register(anyObject(MockEventListener2.class));
++        replay(eventBus);
++
++        final ShiroModule shiroModule = new ShiroModule() {
++            @Override
++            protected void configureShiro() {
++                bindRealm().to(MockRealm.class);
++
++                // bind our event listeners
++                binder().bind(MockEventListener1.class).asEagerSingleton();
++                binder().bind(MockEventListener2.class).asEagerSingleton();
++            }
++
++            @Override
++            protected void bindEventBus(AnnotatedBindingBuilder<EventBus> bind) {
++                bind.toInstance(eventBus);
++            }
++
++            @Provides
++            public MockRealm createRealm() {
++                return mockRealm;
++            }
++
++        };
++        Guice.createInjector(shiroModule);
++
++        verify(eventBus);
++
++    }
++
++    /**
++     * @since 1.4
++     * @throws Exception
++     */
++    @Test
++    public void testEventBusAware() throws Exception {
++
++        final MockRealm mockRealm = createMock(MockRealm.class);
++
++        final ShiroModule shiroModule = new ShiroModule() {
++            @Override
++            protected void configureShiro() {
++                bindRealm().to(MockRealm.class);
++
++                binder().bind(MockEventBusAware.class).asEagerSingleton();
++                expose(MockEventBusAware.class);
++            }
++
++            @Provides
++            public MockRealm createRealm() {
++                return mockRealm;
++            }
++
++        };
++        Injector injector = Guice.createInjector(shiroModule);
++        EventBus eventBus = injector.getInstance(EventBus.class);
++        SecurityManager securityManager = injector.getInstance(SecurityManager.class);
++
++        MockEventBusAware eventBusAware = injector.getInstance(MockEventBusAware.class);
++
++        assertSame(eventBus, eventBusAware.eventBus);
++        assertSame(eventBus, ((DefaultSecurityManager)securityManager).getEventBus());
++    }
++
+     public static interface MockRealm extends Realm {
+ 
+     }
+@@ -227,4 +309,27 @@
+ 
+     public static interface MyDestroyable extends Destroyable {
+     }
++
++    public static class MockEventListener1 {
++        @Subscribe
++        public void listenToAllAndDoNothing(Object o) {}
++    }
++
++    public static class MockEventListener2 {
++        @Subscribe
++        public void listenToAllAndDoNothing(Object o) {}
++    }
++
++    public static class MockEventBusAware implements EventBusAware {
++        private EventBus eventBus;
++
++        public EventBus getEventBus() {
++            return eventBus;
++        }
++
++        @Override
++        public void setEventBus(EventBus eventBus) {
++            this.eventBus = eventBus;
++        }
++    }
+ }
+--- a/support/guice/src/test/java/org/apache/shiro/guice/web/FilterConfigTest.java
++++ b/support/guice/src/test/java/org/apache/shiro/guice/web/FilterConfigTest.java
+@@ -45,7 +45,8 @@
+                 bindRealm().to(ShiroModuleTest.MockRealm.class);
+ 
+                 addFilterChain("/index.html", AUTHC_BASIC);
+-                addFilterChain("/index2.html", config(PERMS, "permission"));
++//                addFilterChain("/index2.html", config(PERMS, "permission"));
++                addFilterChain("/index2.html", filterConfig(PERMS, "permission"));
+             }
+ 
+             @Provides
+--- a/support/guice/src/test/java/org/apache/shiro/guice/web/ShiroWebModuleTest.java
++++ b/support/guice/src/test/java/org/apache/shiro/guice/web/ShiroWebModuleTest.java
+@@ -21,6 +21,7 @@
+ import com.google.inject.Guice;
+ import com.google.inject.Inject;
+ import com.google.inject.Injector;
++import com.google.inject.Key;
+ import com.google.inject.Provides;
+ import com.google.inject.binder.AnnotatedBindingBuilder;
+ import org.apache.shiro.guice.ShiroModuleTest;
+@@ -28,21 +29,38 @@
+ import org.apache.shiro.mgt.SecurityManager;
+ import org.apache.shiro.realm.Realm;
+ import org.apache.shiro.session.mgt.SessionManager;
++import org.apache.shiro.web.env.EnvironmentLoader;
+ import org.apache.shiro.web.env.WebEnvironment;
++import org.apache.shiro.web.filter.authc.BasicHttpAuthenticationFilter;
++import org.apache.shiro.web.filter.authc.FormAuthenticationFilter;
++import org.apache.shiro.web.filter.authz.PermissionsAuthorizationFilter;
++import org.apache.shiro.web.filter.authz.RolesAuthorizationFilter;
+ import org.apache.shiro.web.filter.mgt.FilterChainResolver;
+ import org.apache.shiro.web.mgt.DefaultWebSecurityManager;
+ import org.apache.shiro.web.mgt.WebSecurityManager;
+ import org.apache.shiro.web.session.mgt.DefaultWebSessionManager;
+ import org.apache.shiro.web.session.mgt.ServletContainerSessionManager;
++import org.easymock.EasyMock;
++import org.junit.Assume;
+ import org.junit.Test;
+ 
+ import javax.inject.Named;
++import javax.servlet.Filter;
++import javax.servlet.FilterChain;
++import javax.servlet.FilterConfig;
+ import javax.servlet.ServletContext;
++import javax.servlet.ServletException;
++import javax.servlet.ServletRequest;
++import javax.servlet.ServletResponse;
++import javax.servlet.http.HttpServletRequest;
++import java.io.IOException;
+ import java.util.Collection;
++import java.util.Iterator;
++
++import static org.easymock.EasyMock.*;
++import static org.junit.Assert.*;
++import static org.hamcrest.CoreMatchers.*;
+ 
+-import static org.easymock.EasyMock.createMock;
+-import static org.junit.Assert.assertNotNull;
+-import static org.junit.Assert.assertTrue;
+ 
+ public class ShiroWebModuleTest {
+ 
+@@ -146,6 +164,92 @@
+         assertTrue( environment == webEnvironment );
+     }
+ 
++    /**
++     * @since 1.4
++     */
++    @Test
++    public void testAddFilterChainGuice3and4() {
++
++        final ShiroModuleTest.MockRealm mockRealm = createMock(ShiroModuleTest.MockRealm.class);
++        ServletContext servletContext = createMock(ServletContext.class);
++        HttpServletRequest request = createMock(HttpServletRequest.class);
++
++        servletContext.setAttribute(eq(EnvironmentLoader.ENVIRONMENT_ATTRIBUTE_KEY), EasyMock.anyObject());
++        expect(request.getAttribute("javax.servlet.include.context_path")).andReturn("").anyTimes();
++        expect(request.getCharacterEncoding()).andReturn("UTF-8").anyTimes();
++        expect(request.getAttribute("javax.servlet.include.request_uri")).andReturn("/test_authc");
++        expect(request.getAttribute("javax.servlet.include.request_uri")).andReturn("/test_custom_filter");
++        expect(request.getAttribute("javax.servlet.include.request_uri")).andReturn("/test_authc_basic");
++        expect(request.getAttribute("javax.servlet.include.request_uri")).andReturn("/test_perms");
++        expect(request.getAttribute("javax.servlet.include.request_uri")).andReturn("/multiple_configs");
++        replay(servletContext, request);
++
++        Injector injector = Guice.createInjector(new ShiroWebModule(servletContext) {
++            @Override
++            protected void configureShiroWeb() {
++                bindRealm().to(ShiroModuleTest.MockRealm.class);
++                expose(FilterChainResolver.class);
++                this.addFilterChain("/test_authc/**", filterConfig(AUTHC));
++                this.addFilterChain("/test_custom_filter/**", Key.get(CustomFilter.class));
++                this.addFilterChain("/test_authc_basic/**", AUTHC_BASIC);
++                this.addFilterChain("/test_perms/**", filterConfig(PERMS, "remote:invoke:lan,wan"));
++                this.addFilterChain("/multiple_configs/**", filterConfig(AUTHC), filterConfig(ROLES, "b2bClient"), filterConfig(PERMS, "remote:invoke:lan,wan"));
++            }
++
++            @Provides
++            public ShiroModuleTest.MockRealm createRealm() {
++                return mockRealm;
++            }
++        });
++
++        FilterChainResolver resolver = injector.getInstance(FilterChainResolver.class);
++        assertThat(resolver, instanceOf(SimpleFilterChainResolver.class));
++        SimpleFilterChainResolver simpleFilterChainResolver = (SimpleFilterChainResolver) resolver;
++
++        // test the /test_authc resource
++        FilterChain filterChain = simpleFilterChainResolver.getChain(request, null, null);
++        assertThat(filterChain, instanceOf(SimpleFilterChain.class));
++        Filter nextFilter = getNextFilter((SimpleFilterChain) filterChain);
++        assertThat(nextFilter, instanceOf(FormAuthenticationFilter.class));
++
++        // test the /test_custom_filter resource
++        filterChain = simpleFilterChainResolver.getChain(request, null, null);
++        assertThat(filterChain, instanceOf(SimpleFilterChain.class));
++        nextFilter = getNextFilter((SimpleFilterChain) filterChain);
++        assertThat(nextFilter, instanceOf(CustomFilter.class));
++
++        // test the /test_authc_basic resource
++        filterChain = simpleFilterChainResolver.getChain(request, null, null);
++        assertThat(filterChain, instanceOf(SimpleFilterChain.class));
++        nextFilter = getNextFilter((SimpleFilterChain) filterChain);
++        assertThat(nextFilter, instanceOf(BasicHttpAuthenticationFilter.class));
++
++        // test the /test_perms resource
++        filterChain = simpleFilterChainResolver.getChain(request, null, null);
++        assertThat(filterChain, instanceOf(SimpleFilterChain.class));
++        nextFilter = getNextFilter((SimpleFilterChain) filterChain);
++        assertThat(nextFilter, instanceOf(PermissionsAuthorizationFilter.class));
++
++        // test the /multiple_configs resource
++        filterChain = simpleFilterChainResolver.getChain(request, null, null);
++        assertThat(filterChain, instanceOf(SimpleFilterChain.class));
++        assertThat(getNextFilter((SimpleFilterChain) filterChain), instanceOf(FormAuthenticationFilter.class));
++        assertThat(getNextFilter((SimpleFilterChain) filterChain), instanceOf(RolesAuthorizationFilter.class));
++        assertThat(getNextFilter((SimpleFilterChain) filterChain), instanceOf(PermissionsAuthorizationFilter.class));
++
++        verify(servletContext, request);
++    }
++
++    private Filter getNextFilter(SimpleFilterChain filterChain) {
++
++        Iterator<? extends Filter> filters = filterChain.getFilters();
++        if (filters.hasNext()) {
++            return filters.next();
++        }
++
++        return null;
++    }
++
+     public static class MyDefaultWebSecurityManager extends DefaultWebSecurityManager {
+         @Inject
+         public MyDefaultWebSecurityManager(Collection<Realm> realms) {
+@@ -162,4 +266,16 @@
+             super(filterChainResolver, servletContext, securityManager);
+         }
+     }
++
++    public static class CustomFilter implements Filter {
++
++        @Override
++        public void init(FilterConfig filterConfig) throws ServletException {}
++
++        @Override
++        public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {}
++
++        @Override
++        public void destroy() {}
++    }
+ }
diff -Nru shiro-1.3.2/debian/patches/CVE-2020-13933.patch shiro-1.3.2/debian/patches/CVE-2020-13933.patch
--- shiro-1.3.2/debian/patches/CVE-2020-13933.patch	1969-12-31 19:00:00.000000000 -0500
+++ shiro-1.3.2/debian/patches/CVE-2020-13933.patch	2021-08-06 14:25:38.000000000 -0400
@@ -0,0 +1,1009 @@
+From dc194fc977ab6cfbf3c1ecb085e2bac5db14af6d Mon Sep 17 00:00:00 2001
+From: Brian Demers <bdemers@apache.org>
+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
+@@ -30,6 +30,7 @@
+ import org.apache.shiro.session.mgt.SessionManager;
+ import org.apache.shiro.util.StringUtils;
+ 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;
+@@ -84,7 +85,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";
+ 
+@@ -121,6 +123,12 @@
+         };
+     }
+ 
++    public List<FilterConfig<? extends Filter>> globalFilters() {
++        ArrayList<FilterConfig<? extends Filter>> filters = new ArrayList<FilterConfig<? extends Filter>>();
++        filters.add(filterConfig(INVALID_REQUEST));
++        return Collections.unmodifiableList(filters);
++    }
++
+     @Override
+     protected final void configureShiro() {
+         bindBeanType(TypeLiteral.get(ServletContext.class), Key.get(ServletContext.class, Names.named(NAME)));
+@@ -132,6 +140,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 FilterConfig[0]);
++        }
++
+         bind(FilterChainResolver.class).toProvider(new FilterChainResolverProvider(setupFilterChainConfigs()));
+     }
+ 
+@@ -150,8 +164,15 @@
+             // collect the keys used for this path
+             List<Key<? extends Filter>> keysForPath = new ArrayList<Key<? extends Filter>>();
+ 
+-            for (int i = 0; i < filterChain.getValue().length; i++) {
+-                FilterConfig<? extends Filter> filterConfig = filterChain.getValue()[i];
++            List<FilterConfig<? extends Filter>> globalFilters = this.globalFilters();
++            FilterConfig<? extends Filter>[] pathFilters = filterChain.getValue();
++
++            // merge the global filters and the path specific filters
++            List<FilterConfig<? extends Filter>> filterConfigs = new ArrayList<FilterConfig<? extends Filter>>(globalFilters.size() + pathFilters.length);
++            filterConfigs.addAll(globalFilters);
++            filterConfigs.addAll(Arrays.asList(pathFilters));
++
++            for (FilterConfig<? extends Filter> filterConfig : filterConfigs) {
+ 
+                 Key<? extends Filter> key = filterConfig.getKey();
+                 String config = filterConfig.getConfigValue();
+--- a/support/guice/src/test/java/org/apache/shiro/guice/web/ShiroWebModuleTest.java
++++ b/support/guice/src/test/java/org/apache/shiro/guice/web/ShiroWebModuleTest.java
+@@ -24,6 +24,7 @@
+ import com.google.inject.Key;
+ import com.google.inject.Provides;
+ import com.google.inject.binder.AnnotatedBindingBuilder;
++import com.google.inject.name.Names;
+ import org.apache.shiro.guice.ShiroModuleTest;
+ import org.apache.shiro.env.Environment;
+ import org.apache.shiro.mgt.SecurityManager;
+@@ -31,6 +32,7 @@
+ import org.apache.shiro.session.mgt.SessionManager;
+ import org.apache.shiro.web.env.EnvironmentLoader;
+ import org.apache.shiro.web.env.WebEnvironment;
++import org.apache.shiro.web.filter.InvalidRequestFilter;
+ import org.apache.shiro.web.filter.authc.BasicHttpAuthenticationFilter;
+ import org.apache.shiro.web.filter.authc.FormAuthenticationFilter;
+ import org.apache.shiro.web.filter.authz.PermissionsAuthorizationFilter;
+@@ -55,7 +57,9 @@
+ import javax.servlet.http.HttpServletRequest;
+ import java.io.IOException;
+ import java.util.Collection;
++import java.util.Collections;
+ import java.util.Iterator;
++import java.util.List;
+ 
+ import static org.easymock.EasyMock.*;
+ import static org.junit.Assert.*;
+@@ -212,35 +216,184 @@
+         FilterChain filterChain = simpleFilterChainResolver.getChain(request, null, null);
+         assertThat(filterChain, instanceOf(SimpleFilterChain.class));
+         Filter nextFilter = getNextFilter((SimpleFilterChain) filterChain);
++        assertThat(nextFilter, instanceOf(InvalidRequestFilter.class));
++        nextFilter = getNextFilter((SimpleFilterChain) filterChain);
+         assertThat(nextFilter, instanceOf(FormAuthenticationFilter.class));
+ 
+         // test the /test_custom_filter resource
+         filterChain = simpleFilterChainResolver.getChain(request, null, null);
+         assertThat(filterChain, instanceOf(SimpleFilterChain.class));
+         nextFilter = getNextFilter((SimpleFilterChain) filterChain);
++        assertThat(nextFilter, instanceOf(InvalidRequestFilter.class));
++        nextFilter = getNextFilter((SimpleFilterChain) filterChain);
+         assertThat(nextFilter, instanceOf(CustomFilter.class));
+ 
+         // test the /test_authc_basic resource
+         filterChain = simpleFilterChainResolver.getChain(request, null, null);
+         assertThat(filterChain, instanceOf(SimpleFilterChain.class));
+         nextFilter = getNextFilter((SimpleFilterChain) filterChain);
++        assertThat(nextFilter, instanceOf(InvalidRequestFilter.class));
++        nextFilter = getNextFilter((SimpleFilterChain) filterChain);
+         assertThat(nextFilter, instanceOf(BasicHttpAuthenticationFilter.class));
+ 
+         // test the /test_perms resource
+         filterChain = simpleFilterChainResolver.getChain(request, null, null);
+         assertThat(filterChain, instanceOf(SimpleFilterChain.class));
+         nextFilter = getNextFilter((SimpleFilterChain) filterChain);
++        assertThat(nextFilter, instanceOf(InvalidRequestFilter.class));
++        nextFilter = getNextFilter((SimpleFilterChain) filterChain);
+         assertThat(nextFilter, instanceOf(PermissionsAuthorizationFilter.class));
+ 
+         // test the /multiple_configs resource
+         filterChain = simpleFilterChainResolver.getChain(request, null, null);
+         assertThat(filterChain, instanceOf(SimpleFilterChain.class));
++        assertThat(getNextFilter((SimpleFilterChain) filterChain), instanceOf(InvalidRequestFilter.class));
+         assertThat(getNextFilter((SimpleFilterChain) filterChain), instanceOf(FormAuthenticationFilter.class));
+         assertThat(getNextFilter((SimpleFilterChain) filterChain), instanceOf(RolesAuthorizationFilter.class));
+         assertThat(getNextFilter((SimpleFilterChain) filterChain), instanceOf(PermissionsAuthorizationFilter.class));
+ 
+         verify(servletContext, request);
+     }
++
++    @Test
++    public void testDefaultPath() {
++
++        final ShiroModuleTest.MockRealm mockRealm = createMock(ShiroModuleTest.MockRealm.class);
++        ServletContext servletContext = createMock(ServletContext.class);
++        HttpServletRequest request = createMock(HttpServletRequest.class);
++
++        servletContext.setAttribute(eq(EnvironmentLoader.ENVIRONMENT_ATTRIBUTE_KEY), EasyMock.anyObject());
++        expect(request.getAttribute("javax.servlet.include.context_path")).andReturn("").anyTimes();
++        expect(request.getCharacterEncoding()).andReturn("UTF-8").anyTimes();
++        expect(request.getAttribute("javax.servlet.include.path_info")).andReturn(null).anyTimes();
++        expect(request.getPathInfo()).andReturn(null).anyTimes();
++        expect(request.getAttribute("javax.servlet.include.servlet_path")).andReturn("/test/foobar");
++        replay(servletContext, request);
++
++        Injector injector = Guice.createInjector(new ShiroWebModule(servletContext) {
++            @Override
++            protected void configureShiroWeb() {
++                bindRealm().to(ShiroModuleTest.MockRealm.class);
++                expose(FilterChainResolver.class);
++                // no paths configured
++            }
++
++            @Provides
++            public ShiroModuleTest.MockRealm createRealm() {
++                return mockRealm;
++            }
++        });
++
++        FilterChainResolver resolver = injector.getInstance(FilterChainResolver.class);
++        assertThat(resolver, instanceOf(SimpleFilterChainResolver.class));
++        SimpleFilterChainResolver simpleFilterChainResolver = (SimpleFilterChainResolver) resolver;
++
++        // test the /test_authc resource
++        FilterChain filterChain = simpleFilterChainResolver.getChain(request, null, null);
++        assertThat(filterChain, instanceOf(SimpleFilterChain.class));
++
++        assertThat(getNextFilter((SimpleFilterChain) filterChain), instanceOf(InvalidRequestFilter.class));
++        assertThat(getNextFilter((SimpleFilterChain) filterChain), nullValue());
++
++        verify(servletContext, request);
++    }
++
++    @Test
++    public void testDisableGlobalFilters() {
++
++        final ShiroModuleTest.MockRealm mockRealm = createMock(ShiroModuleTest.MockRealm.class);
++        ServletContext servletContext = createMock(ServletContext.class);
++        HttpServletRequest request = createMock(HttpServletRequest.class);
++
++        servletContext.setAttribute(eq(EnvironmentLoader.ENVIRONMENT_ATTRIBUTE_KEY), EasyMock.anyObject());
++        expect(request.getAttribute("javax.servlet.include.context_path")).andReturn("").anyTimes();
++        expect(request.getCharacterEncoding()).andReturn("UTF-8").anyTimes();
++        expect(request.getAttribute("javax.servlet.include.path_info")).andReturn(null).anyTimes();
++        expect(request.getPathInfo()).andReturn(null).anyTimes();
++        expect(request.getAttribute("javax.servlet.include.servlet_path")).andReturn("/test/foobar");
++        replay(servletContext, request);
++
++        Injector injector = Guice.createInjector(new ShiroWebModule(servletContext) {
++            @Override
++            protected void configureShiroWeb() {
++                bindRealm().to(ShiroModuleTest.MockRealm.class);
++                expose(FilterChainResolver.class);
++                this.addFilterChain("/**", filterConfig(AUTHC));
++            }
++
++            @Override
++            public List<FilterConfig<? extends Filter>> globalFilters() {
++                return Collections.emptyList();
++            }
++
++            @Provides
++            public ShiroModuleTest.MockRealm createRealm() {
++                return mockRealm;
++            }
++        });
++
++        FilterChainResolver resolver = injector.getInstance(FilterChainResolver.class);
++        assertThat(resolver, instanceOf(SimpleFilterChainResolver.class));
++        SimpleFilterChainResolver simpleFilterChainResolver = (SimpleFilterChainResolver) resolver;
++
++        // test the /test_authc resource
++        FilterChain filterChain = simpleFilterChainResolver.getChain(request, null, null);
++        assertThat(filterChain, instanceOf(SimpleFilterChain.class));
++
++        assertThat(getNextFilter((SimpleFilterChain) filterChain), instanceOf(FormAuthenticationFilter.class));
++        assertThat(getNextFilter((SimpleFilterChain) filterChain), nullValue());
++
++        verify(servletContext, request);
++    }
++
++    @Test
++    public void testChangeInvalidFilterConfig() {
++
++        final ShiroModuleTest.MockRealm mockRealm = createMock(ShiroModuleTest.MockRealm.class);
++        ServletContext servletContext = createMock(ServletContext.class);
++        HttpServletRequest request = createMock(HttpServletRequest.class);
++
++        servletContext.setAttribute(eq(EnvironmentLoader.ENVIRONMENT_ATTRIBUTE_KEY), EasyMock.anyObject());
++        expect(request.getAttribute("javax.servlet.include.context_path")).andReturn("").anyTimes();
++        expect(request.getCharacterEncoding()).andReturn("UTF-8").anyTimes();
++        expect(request.getAttribute("javax.servlet.include.path_info")).andReturn(null).anyTimes();
++        expect(request.getPathInfo()).andReturn(null).anyTimes();
++        expect(request.getAttribute("javax.servlet.include.servlet_path")).andReturn("/test/foobar");
++        replay(servletContext, request);
++
++        Injector injector = Guice.createInjector(new ShiroWebModule(servletContext) {
++            @Override
++            protected void configureShiroWeb() {
++
++                bindConstant().annotatedWith(Names.named("shiro.blockBackslash")).to(false);
++
++                bindRealm().to(ShiroModuleTest.MockRealm.class);
++                expose(FilterChainResolver.class);
++                this.addFilterChain("/**", filterConfig(AUTHC));
++            }
++
++            @Provides
++            public ShiroModuleTest.MockRealm createRealm() {
++                return mockRealm;
++            }
++        });
++
++        FilterChainResolver resolver = injector.getInstance(FilterChainResolver.class);
++        assertThat(resolver, instanceOf(SimpleFilterChainResolver.class));
++        SimpleFilterChainResolver simpleFilterChainResolver = (SimpleFilterChainResolver) resolver;
++
++        // test the /test_authc resource
++        FilterChain filterChain = simpleFilterChainResolver.getChain(request, null, null);
++        assertThat(filterChain, instanceOf(SimpleFilterChain.class));
++
++        Filter invalidRequestFilter = getNextFilter((SimpleFilterChain) filterChain);
++        assertThat(invalidRequestFilter, instanceOf(InvalidRequestFilter.class));
++        assertFalse("Expected 'blockBackslash' to be false", ((InvalidRequestFilter) invalidRequestFilter).isBlockBackslash());
++        assertThat(getNextFilter((SimpleFilterChain) filterChain), instanceOf(FormAuthenticationFilter.class));
++        assertThat(getNextFilter((SimpleFilterChain) filterChain), nullValue());
++
++        verify(servletContext, request);
++    }
+ 
+     private Filter getNextFilter(SimpleFilterChain filterChain) {
+ 
+--- /dev/null
++++ b/support/spring-boot/spring-boot-web-starter/src/test/groovy/org/apache/shiro/spring/boot/autoconfigure/web/ConfiguredGlobalFiltersTest.groovy
+@@ -0,0 +1,104 @@
++/*
++ * 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.boot.autoconfigure.web
++
++import org.apache.shiro.spring.boot.autoconfigure.web.application.ShiroWebAutoConfigurationTestApplication
++import org.apache.shiro.spring.web.ShiroFilterFactoryBean
++import org.apache.shiro.spring.web.config.AbstractShiroWebFilterConfiguration
++import org.apache.shiro.web.filter.InvalidRequestFilter
++import org.apache.shiro.web.filter.authz.PortFilter
++import org.apache.shiro.web.filter.mgt.DefaultFilter
++import org.apache.shiro.web.filter.mgt.DefaultFilterChainManager
++import org.apache.shiro.web.filter.mgt.NamedFilterList
++import org.apache.shiro.web.servlet.AbstractShiroFilter
++import org.junit.Test
++import org.junit.runner.RunWith
++import org.springframework.beans.factory.annotation.Autowired
++import org.springframework.boot.test.context.SpringBootTest
++import org.springframework.context.annotation.Bean
++import org.springframework.context.annotation.Configuration
++import org.springframework.test.context.junit4.SpringRunner
++
++import static org.hamcrest.MatcherAssert.assertThat
++import static org.hamcrest.Matchers.*
++
++@RunWith(SpringRunner.class)
++@SpringBootTest(classes = [ShiroWebAutoConfigurationTestApplication, Config])
++
++class ConfiguredGlobalFiltersTest {
++
++    @Configuration
++    static class Config extends AbstractShiroWebFilterConfiguration {
++
++        @Bean
++        List<String> globalFilters() {
++            return [DefaultFilter.invalidRequest.name(), DefaultFilter.port.name()]
++        }
++
++        @Bean
++        @Override
++        ShiroFilterFactoryBean shiroFilterFactoryBean() {
++            ShiroFilterFactoryBean bean = super.shiroFilterFactoryBean()
++            InvalidRequestFilter invalidRequestFilter = new InvalidRequestFilter()
++            invalidRequestFilter.setBlockBackslash(false)
++            PortFilter portFilter = new PortFilter()
++            portFilter.setPort(9999)
++            bean.getFilters().put("invalidRequest", invalidRequestFilter)
++            bean.getFilters().put("port", portFilter)
++            return bean
++        }
++    }
++
++    @Autowired
++    private AbstractShiroFilter shiroFilter
++
++    @Test
++    void testGlobalFiltersConfigured() {
++        // make sure global chains are configured
++        assertThat shiroFilter.filterChainResolver.filterChainManager, instanceOf(DefaultFilterChainManager)
++        DefaultFilterChainManager filterChainManager = shiroFilter.filterChainResolver.filterChainManager
++
++        // default config set
++        assertThat filterChainManager.globalFilterNames, contains(DefaultFilter.invalidRequest.name(),
++                                                                  DefaultFilter.port.name())
++        // default route configured
++        NamedFilterList allChain = filterChainManager.getChain("/**")
++        assertThat allChain, contains(
++                instanceOf(DefaultFilter.invalidRequest.filterClass),
++                instanceOf(DefaultFilter.port.filterClass))
++
++        InvalidRequestFilter invalidRequest = allChain.get(0)
++        assertThat "Expected invalidRequest.blockBackslash to be false", !invalidRequest.isBlockBackslash()
++        PortFilter portFilter = allChain.get(1) // an ugly line, but we want to make sure that we can override the filters
++        // defined in Shiro's DefaultFilter
++        assertThat portFilter.port, equalTo(9999)
++
++        // configured routes also contain global filters
++        NamedFilterList loginChain = filterChainManager.getChain("/login.html")
++        assertThat loginChain, contains(
++                instanceOf(DefaultFilter.invalidRequest.filterClass),
++                instanceOf(DefaultFilter.port.filterClass),
++                instanceOf(DefaultFilter.authc.filterClass)) // configured in ShiroWebAutoConfigurationTestApplication
++
++        assertThat loginChain.get(0), sameInstance(invalidRequest)
++        assertThat loginChain.get(1), sameInstance(portFilter)
++
++
++    }
++}
+--- /dev/null
++++ b/support/spring-boot/spring-boot-web-starter/src/test/groovy/org/apache/shiro/spring/boot/autoconfigure/web/DisabledGlobalFiltersTest.groovy
+@@ -0,0 +1,64 @@
++/*
++ * 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.boot.autoconfigure.web;
++
++import org.apache.shiro.spring.boot.autoconfigure.web.application.ShiroWebAutoConfigurationTestApplication
++import org.apache.shiro.web.filter.mgt.DefaultFilterChainManager
++import org.apache.shiro.web.servlet.AbstractShiroFilter
++import org.junit.Test
++import org.junit.runner.RunWith
++import org.springframework.beans.factory.annotation.Autowired
++import org.springframework.boot.test.context.SpringBootTest
++import org.springframework.context.annotation.Bean
++import org.springframework.context.annotation.Configuration
++import org.springframework.test.context.junit4.SpringRunner
++
++import static org.hamcrest.MatcherAssert.assertThat
++import static org.hamcrest.Matchers.equalTo
++import static org.hamcrest.Matchers.instanceOf
++import static org.hamcrest.Matchers.nullValue
++
++@RunWith(SpringRunner.class)
++@SpringBootTest(classes = [ShiroWebAutoConfigurationTestApplication, Config])
++class DisabledGlobalFiltersTest {
++
++    @Configuration
++    static class Config {
++
++        @Bean
++        List<String> globalFilters() {
++            return []
++        }
++    }
++
++    @Autowired
++    private AbstractShiroFilter shiroFilter
++
++    @Test
++    void testGlobalFiltersDisabled() {
++        // make sure global chains are configured
++        assertThat shiroFilter.filterChainResolver.filterChainManager, instanceOf(DefaultFilterChainManager)
++        DefaultFilterChainManager filterChainManager = shiroFilter.filterChainResolver.filterChainManager
++
++        // default config set
++        assertThat filterChainManager.globalFilterNames, equalTo([])
++        // default route configured
++        assertThat filterChainManager.getChain("/**"), nullValue()
++    }
++}
+--- 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;
+     }
+ 
+@@ -533,6 +555,7 @@
+                 throw new IllegalArgumentException("WebSecurityManager property cannot be null.");
+             }
+             setSecurityManager(webSecurityManager);
++
+             if (resolver != null) {
+                 setFilterChainResolver(resolver);
+             }
+--- 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
+@@ -18,6 +18,7 @@
+  */
+ 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;
+@@ -55,11 +56,12 @@
+         DefaultFilterChainManager fcManager = (DefaultFilterChainManager) resolver.getFilterChainManager();
+         NamedFilterList chain = fcManager.getChain("/test");
+         assertNotNull(chain);
+-        assertEquals(chain.size(), 2);
++        assertEquals(chain.size(), 3);
+         Filter[] filters = new Filter[chain.size()];
+         filters = chain.toArray(filters);
+-        assertTrue(filters[0] instanceof DummyFilter);
+-        assertTrue(filters[1] instanceof FormAuthenticationFilter);
++        assertTrue(filters[0] instanceof InvalidRequestFilter); // global filter
++        assertTrue(filters[1] instanceof DummyFilter);
++        assertTrue(filters[2] instanceof FormAuthenticationFilter);
+     }
+ 
+     /**
+--- 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;
+ 
+ /**
+@@ -51,6 +54,8 @@
+ 
+     private Map<String, ?> defaultBeans;
+ 
++    private List<String> globalFilters = Collections.singletonList(DefaultFilter.invalidRequest.name());
++
+     public IniFilterChainResolverFactory() {
+         super();
+     }
+@@ -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;
+ }
+--- a/web/src/main/java/org/apache/shiro/web/servlet/AbstractShiroFilter.java
++++ b/web/src/main/java/org/apache/shiro/web/servlet/AbstractShiroFilter.java
+@@ -404,6 +404,7 @@
+      * @since 1.0
+      */
+     protected FilterChain getExecutionChain(ServletRequest request, ServletResponse response, FilterChain origChain) {
++
+         FilterChain chain = origChain;
+ 
+         FilterChainResolver resolver = getFilterChainResolver();
+--- /dev/null
++++ b/web/src/test/java/org/apache/shiro/web/env/FilterStub.java
+@@ -0,0 +1,45 @@
++/*
++ * 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.env;
++
++import javax.servlet.Filter;
++import javax.servlet.FilterChain;
++import javax.servlet.FilterConfig;
++import javax.servlet.ServletException;
++import javax.servlet.ServletRequest;
++import javax.servlet.ServletResponse;
++import java.io.IOException;
++
++public class FilterStub implements Filter {
++
++    @Override
++    public void init(FilterConfig filterConfig) throws ServletException {
++
++    }
++
++    @Override
++    public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
++
++    }
++
++    @Override
++    public void destroy() {
++
++    }
++}
diff -Nru shiro-1.3.2/debian/patches/CVE-2020-17510_1_of_2.patch shiro-1.3.2/debian/patches/CVE-2020-17510_1_of_2.patch
--- shiro-1.3.2/debian/patches/CVE-2020-17510_1_of_2.patch	1969-12-31 19:00:00.000000000 -0500
+++ shiro-1.3.2/debian/patches/CVE-2020-17510_1_of_2.patch	2021-08-06 14:25:38.000000000 -0400
@@ -0,0 +1,236 @@
+From a28300448ae6c4bb78a8ba626b0cacb00f82d5f8 Mon Sep 17 00:00:00 2001
+From: Brian Demers <bdemers@apache.org>
+Date: Thu, 3 Sep 2020 14:58:45 -0400
+Subject: [PATCH] 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
+---
+ .../web/filter/InvalidRequestFilter.java      | 22 ++++--
+ .../org/apache/shiro/web/util/WebUtils.java   |  4 +-
+ .../filter/InvalidRequestFilterTest.groovy    | 48 +++++++++++--
+ .../apache/shiro/web/util/WebUtilsTest.groovy | 52 ++++++++++++++
+ .../shiro/web/RestoreSystemProperties.java    | 69 +++++++++++++++++++
+ 5 files changed, 182 insertions(+), 13 deletions(-)
+ create mode 100644 web/src/test/java/org/apache/shiro/web/RestoreSystemProperties.java
+
+--- 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.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 @@
+ 
+     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
+--- a/web/src/main/java/org/apache/shiro/web/util/WebUtils.java
++++ b/web/src/main/java/org/apache/shiro/web/util/WebUtils.java
+@@ -56,6 +56,8 @@
+     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}.
+@@ -162,7 +164,7 @@
+      * @return normalized path
+      */
+     public static String normalize(String path) {
+-        return normalize(path, true);
++        return normalize(path, Boolean.getBoolean(ALLOW_BACKSLASH));
+     }
+ 
+     /**
+--- 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 @@
+         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)
+--- /dev/null
++++ b/web/src/test/java/org/apache/shiro/web/RestoreSystemProperties.java
+@@ -0,0 +1,74 @@
++/*
++ * Licensed to the Apache Software Foundation (ASF) under one
++ * or more contributor license agreements.  See the NOTICE file
++ * distributed with this work for additional information
++ * regarding copyright ownership.  The ASF licenses this file
++ * to you under the Apache License, Version 2.0 (the
++ * "License"); you may not use this file except in compliance
++ * with the License.  You may obtain a copy of the License at
++ *
++ *     http://www.apache.org/licenses/LICENSE-2.0
++ *
++ * Unless required by applicable law or agreed to in writing,
++ * software distributed under the License is distributed on an
++ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
++ * KIND, either express or implied.  See the License for the
++ * specific language governing permissions and limitations
++ * under the License.
++ */
++package org.apache.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.<String, String>emptyMap(), closure);
++    }
++
++    public static <T> T withProperties(Map<String, String> properties, Closure<T> closure) {
++
++        RestoreSystemProperties restoreSystemProperties = new RestoreSystemProperties();
++        try {
++            for (Map.Entry<String, String> property : properties.entrySet()) {
++                System.setProperty(property.getKey(), property.getValue());
++            }
++
++            return closure.call();
++        } finally {
++            restoreSystemProperties.close();
++        }
++    }
++
++    @Override
++    public void close() {
++        restore();
++    }
++}
diff -Nru shiro-1.3.2/debian/patches/CVE-2020-17510_2_of_2.patch shiro-1.3.2/debian/patches/CVE-2020-17510_2_of_2.patch
--- shiro-1.3.2/debian/patches/CVE-2020-17510_2_of_2.patch	1969-12-31 19:00:00.000000000 -0500
+++ shiro-1.3.2/debian/patches/CVE-2020-17510_2_of_2.patch	2021-08-06 14:25:38.000000000 -0400
@@ -0,0 +1,67 @@
+From 74d4cb6aee9aa1af4b098edc526a1e5630743f9b Mon Sep 17 00:00:00 2001
+From: Brian Demers <bdemers@apache.org>
+Date: Tue, 29 Sep 2020 17:59:29 -0400
+Subject: [PATCH] Disable jsessionid URL rewriting by default
+
+This matches the default of the InvalidRequestFilter
+
+Fixes: SHIRO-795
+---
+ .../spring/web/config/AbstractShiroWebConfiguration.java     | 2 +-
+ .../shiro/web/session/mgt/DefaultWebSessionManager.java      | 2 +-
+ .../web/session/mgt/DefaultWebSessionManagerTest.groovy      | 5 ++++-
+ 3 files changed, 6 insertions(+), 3 deletions(-)
+
+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 eb7eda1f..9aa275a9 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 DefaultWebSessionManager() {
+         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 841569fc..35b31204 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);
+-- 
+2.20.1
+
diff -Nru shiro-1.3.2/debian/patches/CVE-2020-1957.patch shiro-1.3.2/debian/patches/CVE-2020-1957.patch
--- shiro-1.3.2/debian/patches/CVE-2020-1957.patch	1969-12-31 19:00:00.000000000 -0500
+++ shiro-1.3.2/debian/patches/CVE-2020-1957.patch	2021-08-06 14:25:38.000000000 -0400
@@ -0,0 +1,297 @@
+--- a/web/src/main/java/org/apache/shiro/web/util/WebUtils.java
++++ b/web/src/main/java/org/apache/shiro/web/util/WebUtils.java
+@@ -108,16 +108,7 @@
+      * @return the path within the web application
+      */
+     public static String getPathWithinApplication(HttpServletRequest request) {
+-        String contextPath = getContextPath(request);
+-        String requestUri = getRequestUri(request);
+-        if (StringUtils.startsWithIgnoreCase(requestUri, contextPath)) {
+-            // Normal case: URI contains context path.
+-            String path = requestUri.substring(contextPath.length());
+-            return (StringUtils.hasText(path) ? path : "/");
+-        } else {
+-            // Special case: rather unusual.
+-            return requestUri;
+-        }
++        return normalize(removeSemicolon(getServletPath(request) + getPathInfo(request)));
+     }
+ 
+     /**
+@@ -131,7 +122,9 @@
+      *
+      * @param request current HTTP request
+      * @return the request URI
++     * @deprecated use getPathWithinApplication() to get the path minus the context path, or call HttpServletRequest.getRequestURI() directly from your code.
+      */
++    @Deprecated
+     public static String getRequestUri(HttpServletRequest request) {
+         String uri = (String) request.getAttribute(INCLUDE_REQUEST_URI_ATTRIBUTE);
+         if (uri == null) {
+@@ -140,6 +133,23 @@
+         return normalize(decodeAndCleanUriString(request, uri));
+     }
+ 
++    private static String getServletPath(HttpServletRequest request) {
++        String servletPath = (String) request.getAttribute(INCLUDE_SERVLET_PATH_ATTRIBUTE);
++        return servletPath != null ? servletPath : valueOrEmpty(request.getServletPath());
++    }
++
++    private static String getPathInfo(HttpServletRequest request) {
++        String pathInfo = (String) request.getAttribute(INCLUDE_PATH_INFO_ATTRIBUTE);
++        return pathInfo != null ? pathInfo : valueOrEmpty(request.getPathInfo());
++    }
++
++    private static String valueOrEmpty(String input) {
++        if (input == null) {
++            return "";
++        }
++        return input;
++    }
++
+     /**
+      * Normalize a relative URI path that may have relative values ("/./",
+      * "/../", and so on ) it it.  <strong>WARNING</strong> - This method is
+@@ -230,6 +240,10 @@
+      */
+     private static String decodeAndCleanUriString(HttpServletRequest request, String uri) {
+         uri = decodeRequestString(request, uri);
++        return removeSemicolon(uri);
++    }
++
++    private static String removeSemicolon(String uri) {
+         int semicolonIndex = uri.indexOf(';');
+         return (semicolonIndex != -1 ? uri.substring(0, semicolonIndex) : uri);
+     }
+--- a/support/guice/src/test/java/org/apache/shiro/guice/web/FilterConfigTest.java
++++ b/support/guice/src/test/java/org/apache/shiro/guice/web/FilterConfigTest.java
+@@ -85,9 +85,8 @@
+     private HttpServletRequest createMockRequest(String path) {
+         HttpServletRequest request = createNiceMock(HttpServletRequest.class);
+ 
+-        expect(request.getAttribute(WebUtils.INCLUDE_CONTEXT_PATH_ATTRIBUTE)).andReturn(null).anyTimes();
+-        expect(request.getContextPath()).andReturn("");
+-        expect(request.getRequestURI()).andReturn(path);
++        expect(request.getServletPath()).andReturn("");
++        expect(request.getPathInfo()).andReturn(path);
+         replay(request);
+         return request;
+     }
+--- a/web/src/test/groovy/org/apache/shiro/web/util/WebUtilsTest.groovy
++++ b/web/src/test/groovy/org/apache/shiro/web/util/WebUtilsTest.groovy
+@@ -140,34 +140,90 @@
+ 
+     }
+ 
++    @Test
++    void testGetRequestUriWithServlet() {
++
++        dotTestGetPathWithinApplicationFromRequest("/servlet", "/foobar", "/servlet/foobar")
++        dotTestGetPathWithinApplicationFromRequest("/servlet", "/foobar", "/servlet/foobar")
++        dotTestGetPathWithinApplicationFromRequest("servlet", "/foobar", "/servlet/foobar")
++        dotTestGetPathWithinApplicationFromRequest("servlet", "/foobar", "/servlet/foobar")
++        dotTestGetPathWithinApplicationFromRequest("servlet", "/foobar", "/servlet/foobar")
++        dotTestGetPathWithinApplicationFromRequest("//servlet", "//foobar", "/servlet/foobar")
++        dotTestGetPathWithinApplicationFromRequest("/servlet", "/foobar", "/servlet/foobar")
++        dotTestGetPathWithinApplicationFromRequest("//servlet", "//foobar", "/servlet/foobar")
++        dotTestGetPathWithinApplicationFromRequest("/servlet", "/../servlet/other", "/servlet/other")
++        dotTestGetPathWithinApplicationFromRequest("/asdf", "/../servlet/other", "/servlet/other")
++        dotTestGetPathWithinApplicationFromRequest("/asdf/foo", ";/../servlet/other", "/asdf/foo")
++        dotTestGetPathWithinApplicationFromRequest("/servlet", "/foobar", "/servlet/foobar")
++        dotTestGetPathWithinApplicationFromRequest("/servlet", "/foobar", "/servlet/foobar")
++        dotTestGetPathWithinApplicationFromRequest("/servlet", "/foobar", "/servlet/foobar")
++        dotTestGetPathWithinApplicationFromRequest(null, null, "/")
++        dotTestGetPathWithinApplicationFromRequest("index.jsp", null, "/index.jsp")
++    }
+ 
+     @Test
+     void testGetPathWithinApplication() {
+ 
+-        doTestGetPathWithinApplication("/", "/foobar", "/foobar");
+-        doTestGetPathWithinApplication("", "/foobar", "/foobar");
+-        doTestGetPathWithinApplication("", "foobar", "/foobar");
+-        doTestGetPathWithinApplication("/", "foobar", "/foobar");
+-        doTestGetPathWithinApplication("//", "foobar", "/foobar");
+-        doTestGetPathWithinApplication("//", "//foobar", "/foobar");
+-        doTestGetPathWithinApplication("/context-path", "/context-path/foobar", "/foobar");
+-        doTestGetPathWithinApplication("/context-path", "/context-path/foobar/", "/foobar/");
+-        doTestGetPathWithinApplication("//context-path", "//context-path/foobar", "/foobar");
+-        doTestGetPathWithinApplication("//context-path", "//context-path//foobar", "/foobar");
+-        doTestGetPathWithinApplication("//context-path", "//context-path/remove-one/remove-two/../../././/foobar", "/foobar");
+-        doTestGetPathWithinApplication("//context-path", "//context-path//../../././/foobar", null);
+-        doTestGetPathWithinApplication("/context%2525path", "/context%2525path/foobar", "/foobar");
+-        doTestGetPathWithinApplication("/c%6Fntext%20path", "/c%6Fntext%20path/foobar", "/foobar");
+-        doTestGetPathWithinApplication("/context path", "/context path/foobar", "/foobar");
++        doTestGetPathWithinApplication("/foobar", null, "/foobar");
++        doTestGetPathWithinApplication("/foobar", "", "/foobar");
++        doTestGetPathWithinApplication("", "/", "/");
++        doTestGetPathWithinApplication("", null, "/");
++        doTestGetPathWithinApplication("/foobar", "//", "/foobar/");
++        doTestGetPathWithinApplication("/foobar", "//extra", "/foobar/extra");
++        doTestGetPathWithinApplication("/foobar", "//extra///", "/foobar/extra/");
++        doTestGetPathWithinApplication("/foo bar", "/path info" ,"/foo bar/path info");
++    }
+ 
++    @Test
++    void testGetRequestURI() {
++        doTestGetRequestURI("/foobar", "/foobar")
++        doTestGetRequestURI( "/foobar/", "/foobar/")
++        doTestGetRequestURI("",  "/");
++        doTestGetRequestURI("foobar", "/foobar");
++        doTestGetRequestURI("//foobar", "/foobar");
++        doTestGetRequestURI("//foobar///", "/foobar/");
++        doTestGetRequestURI("/context-path/foobar", "/context-path/foobar");
++        doTestGetRequestURI("/context-path/foobar/", "/context-path/foobar/");
++        doTestGetRequestURI("//context-path/foobar", "/context-path/foobar");
++        doTestGetRequestURI("//context-path//foobar", "/context-path/foobar");
++        doTestGetRequestURI("//context-path/remove-one/remove-two/../../././/foobar", "/context-path/foobar");
++        doTestGetRequestURI("//context-path//../../././/foobar", null);
++        doTestGetRequestURI("/context%2525path/foobar", "/context%25path/foobar");
++        doTestGetRequestURI("/c%6Fntext%20path/foobar", "/context path/foobar");
++        doTestGetRequestURI("/context path/foobar", "/context path/foobar");
+     }
+ 
+-    void doTestGetPathWithinApplication(String contextPath, String requestUri, String expectedValue) {
++    void doTestGetPathWithinApplication(String servletPath, String pathInfo, String expectedValue) {
+ 
+         def request = createMock(HttpServletRequest)
+-        expect(request.getAttribute(WebUtils.INCLUDE_CONTEXT_PATH_ATTRIBUTE)).andReturn(contextPath)
+-        expect(request.getAttribute(WebUtils.INCLUDE_REQUEST_URI_ATTRIBUTE)).andReturn(requestUri)
+-        expect(request.getCharacterEncoding()).andReturn("UTF-8").times(2)
++        expect(request.getAttribute(WebUtils.INCLUDE_SERVLET_PATH_ATTRIBUTE)).andReturn(servletPath)
++        expect(request.getAttribute(WebUtils.INCLUDE_PATH_INFO_ATTRIBUTE)).andReturn(pathInfo)
++        if (pathInfo == null) {
++            expect(request.getPathInfo()).andReturn(null) // path info can be null
++        }
++        replay request
++        assertEquals expectedValue, WebUtils.getPathWithinApplication(request)
++        verify request
++    }
++
++    void doTestGetRequestURI(String rawRequestUri, String expectedValue) {
++
++        def request = createMock(HttpServletRequest)
++        expect(request.getAttribute(WebUtils.INCLUDE_REQUEST_URI_ATTRIBUTE)).andReturn(rawRequestUri)
++        expect(request.getCharacterEncoding()).andReturn("UTF-8").times(1)
++        replay request
++        assertEquals expectedValue, WebUtils.getRequestUri(request)
++        verify request
++    }
++
++    void dotTestGetPathWithinApplicationFromRequest(String servletPath, String pathInfo, String expectedValue) {
++
++        HttpServletRequest request = createMock(HttpServletRequest)
++        expect(request.getAttribute(WebUtils.INCLUDE_SERVLET_PATH_ATTRIBUTE)).andReturn(null)
++        expect(request.getAttribute(WebUtils.INCLUDE_PATH_INFO_ATTRIBUTE)).andReturn(null)
++        expect(request.getServletPath()).andReturn(servletPath)
++        expect(request.getPathInfo()).andReturn(pathInfo)
++        expect(request.getCharacterEncoding()).andReturn("UTF-8").anyTimes()
+         replay request
+         assertEquals expectedValue, WebUtils.getPathWithinApplication(request)
+         verify request
+--- a/web/src/test/java/org/apache/shiro/web/filter/PathMatchingFilterTest.java
++++ b/web/src/test/java/org/apache/shiro/web/filter/PathMatchingFilterTest.java
+@@ -112,6 +112,8 @@
+ 
+         expect(request.getContextPath()).andReturn(CONTEXT_PATH).anyTimes();
+         expect(request.getRequestURI()).andReturn(ENABLED_PATH).anyTimes();
++        expect(request.getServletPath()).andReturn("").anyTimes();
++        expect(request.getPathInfo()).andReturn(ENABLED_PATH).anyTimes();
+         replay(request);
+ 
+         boolean continueFilterChain = filter.preHandle(request, response);
+--- a/web/src/test/java/org/apache/shiro/web/filter/mgt/PathMatchingFilterChainResolverTest.java
++++ b/web/src/test/java/org/apache/shiro/web/filter/mgt/PathMatchingFilterChainResolverTest.java
+@@ -97,9 +97,8 @@
+         //ensure at least one chain is defined:
+         resolver.getFilterChainManager().addToChain("/index.html", "authcBasic");
+ 
+-        expect(request.getAttribute(WebUtils.INCLUDE_CONTEXT_PATH_ATTRIBUTE)).andReturn(null).anyTimes();
+-        expect(request.getContextPath()).andReturn("");
+-        expect(request.getRequestURI()).andReturn("/index.html");
++        expect(request.getServletPath()).andReturn("");
++        expect(request.getPathInfo()).andReturn("/index.html");
+         replay(request);
+ 
+         FilterChain resolved = resolver.getChain(request, response, chain);
+@@ -116,9 +115,8 @@
+         //ensure at least one chain is defined:
+         resolver.getFilterChainManager().addToChain("/index.html", "authcBasic");
+ 
+-        expect(request.getAttribute(WebUtils.INCLUDE_CONTEXT_PATH_ATTRIBUTE)).andReturn(null).anyTimes();
+-        expect(request.getContextPath()).andReturn("");
+-        expect(request.getRequestURI()).andReturn("/./index.html");
++        expect(request.getServletPath()).andReturn("/");
++        expect(request.getPathInfo()).andReturn("./index.html");
+         replay(request);
+ 
+         FilterChain resolved = resolver.getChain(request, response, chain);
+@@ -135,9 +133,8 @@
+         //ensure at least one chain is defined:
+         resolver.getFilterChainManager().addToChain("/index.html", "authcBasic");
+ 
+-        expect(request.getAttribute(WebUtils.INCLUDE_CONTEXT_PATH_ATTRIBUTE)).andReturn(null).anyTimes();
+-        expect(request.getContextPath()).andReturn("");
+-        expect(request.getRequestURI()).andReturn("/public/../index.html");
++        expect(request.getServletPath()).andReturn("/public/");
++        expect(request.getPathInfo()).andReturn("../index.html");
+         replay(request);
+ 
+         FilterChain resolved = resolver.getChain(request, response, chain);
+@@ -154,9 +151,8 @@
+         //ensure at least one chain is defined:
+         resolver.getFilterChainManager().addToChain("/index.html", "authcBasic");
+ 
+-        expect(request.getAttribute(WebUtils.INCLUDE_CONTEXT_PATH_ATTRIBUTE)).andReturn(null).anyTimes();
+-        expect(request.getContextPath()).andReturn("");
+-        expect(request.getRequestURI()).andReturn("/");
++        expect(request.getServletPath()).andReturn("/");
++        expect(request.getPathInfo()).andReturn(null);
+         replay(request);
+ 
+         FilterChain resolved = resolver.getChain(request, response, chain);
+--- a/support/guice/src/test/java/org/apache/shiro/guice/web/SimpleFilterChainResolverTest.java
++++ b/support/guice/src/test/java/org/apache/shiro/guice/web/SimpleFilterChainResolverTest.java
+@@ -82,8 +82,8 @@
+         ServletResponse response = ctrl.createMock(HttpServletResponse.class);
+         FilterChain originalChain = ctrl.createMock(FilterChain.class);
+ 
+-        expect(request.getAttribute(WebUtils.INCLUDE_CONTEXT_PATH_ATTRIBUTE)).andReturn("/context");
+-        expect(request.getAttribute(WebUtils.INCLUDE_REQUEST_URI_ATTRIBUTE)).andReturn("/mychain");
++        expect(request.getAttribute(WebUtils.INCLUDE_SERVLET_PATH_ATTRIBUTE)).andReturn("/mychain");
++        expect(request.getAttribute(WebUtils.INCLUDE_PATH_INFO_ATTRIBUTE)).andReturn("");
+ 
+         expect(request.getCharacterEncoding()).andStubReturn(null);
+ 
+@@ -113,8 +113,8 @@
+ 
+         ctrl.reset();
+ 
+-        expect(request.getAttribute(WebUtils.INCLUDE_CONTEXT_PATH_ATTRIBUTE)).andReturn("/context");
+-        expect(request.getAttribute(WebUtils.INCLUDE_REQUEST_URI_ATTRIBUTE)).andReturn("/nochain");
++        expect(request.getAttribute(WebUtils.INCLUDE_SERVLET_PATH_ATTRIBUTE)).andReturn("/nochain");
++        expect(request.getAttribute(WebUtils.INCLUDE_PATH_INFO_ATTRIBUTE)).andReturn("");
+ 
+         expect(request.getCharacterEncoding()).andStubReturn(null);
+ 
+--- a/support/guice/src/test/java/org/apache/shiro/guice/web/ShiroWebModuleTest.java
++++ b/support/guice/src/test/java/org/apache/shiro/guice/web/ShiroWebModuleTest.java
+@@ -177,11 +177,13 @@
+         servletContext.setAttribute(eq(EnvironmentLoader.ENVIRONMENT_ATTRIBUTE_KEY), EasyMock.anyObject());
+         expect(request.getAttribute("javax.servlet.include.context_path")).andReturn("").anyTimes();
+         expect(request.getCharacterEncoding()).andReturn("UTF-8").anyTimes();
+-        expect(request.getAttribute("javax.servlet.include.request_uri")).andReturn("/test_authc");
+-        expect(request.getAttribute("javax.servlet.include.request_uri")).andReturn("/test_custom_filter");
+-        expect(request.getAttribute("javax.servlet.include.request_uri")).andReturn("/test_authc_basic");
+-        expect(request.getAttribute("javax.servlet.include.request_uri")).andReturn("/test_perms");
+-        expect(request.getAttribute("javax.servlet.include.request_uri")).andReturn("/multiple_configs");
++        expect(request.getAttribute("javax.servlet.include.path_info")).andReturn(null).anyTimes();
++        expect(request.getPathInfo()).andReturn(null).anyTimes();
++        expect(request.getAttribute("javax.servlet.include.servlet_path")).andReturn("/test_authc");
++        expect(request.getAttribute("javax.servlet.include.servlet_path")).andReturn("/test_custom_filter");
++        expect(request.getAttribute("javax.servlet.include.servlet_path")).andReturn("/test_authc_basic");
++        expect(request.getAttribute("javax.servlet.include.servlet_path")).andReturn("/test_perms");
++        expect(request.getAttribute("javax.servlet.include.servlet_path")).andReturn("/multiple_configs");
+         replay(servletContext, request);
+ 
+         Injector injector = Guice.createInjector(new ShiroWebModule(servletContext) {
diff -Nru shiro-1.3.2/debian/patches/series shiro-1.3.2/debian/patches/series
--- shiro-1.3.2/debian/patches/series	2019-03-01 16:36:03.000000000 -0500
+++ shiro-1.3.2/debian/patches/series	2021-08-06 14:25:38.000000000 -0400
@@ -2,3 +2,8 @@
 02-reproducible-build.patch
 03-spring-compatibility.patch
 04-java11-compatibility.patch
+05-guice-improvements.patch
+CVE-2020-1957.patch
+CVE-2020-13933.patch
+CVE-2020-17510_1_of_2.patch
+CVE-2020-17510_2_of_2.patch

--- End Message ---
--- Begin Message ---
Package: release.debian.org
Version: 10.11

Hi,

The updates relating to these bugs were included in this morning's
10.11 point release for buster.

Regards,

Adam

--- End Message ---

Reply to: