001/*
002 * Licensed to the Apache Software Foundation (ASF) under one
003 * or more contributor license agreements.  See the NOTICE file
004 * distributed with this work for additional information
005 * regarding copyright ownership.  The ASF licenses this file
006 * to you under the Apache License, Version 2.0 (the
007 * "License"); you may not use this file except in compliance
008 * with the License.  You may obtain a copy of the License at
009 *
010 *     http://www.apache.org/licenses/LICENSE-2.0
011 *
012 * Unless required by applicable law or agreed to in writing,
013 * software distributed under the License is distributed on an
014 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
015 * KIND, either express or implied.  See the License for the
016 * specific language governing permissions and limitations
017 * under the License.
018 */
019package org.apache.shiro.web.filter.mgt;
020
021import org.apache.shiro.config.ConfigurationException;
022
023import javax.servlet.Filter;
024import javax.servlet.FilterChain;
025import java.util.List;
026import java.util.Map;
027import java.util.Set;
028
029/**
030 * A {@code FilterChainManager} manages the creation and modification of {@link Filter} chains from an available pool
031 * of {@link Filter} instances.
032 *
033 * @since 1.0
034 */
035public interface FilterChainManager {
036
037    /**
038     * Returns the pool of available {@code Filter}s managed by this manager, keyed by {@code name}.
039     *
040     * @return the pool of available {@code Filter}s managed by this manager, keyed by {@code name}.
041     */
042    Map<String, Filter> getFilters();
043
044    /**
045     * Returns the filter chain identified by the specified {@code chainName} or {@code null} if there is no chain with
046     * that name.
047     *
048     * @param chainName the name identifying the filter chain.
049     * @return the filter chain identified by the specified {@code chainName} or {@code null} if there is no chain with
050     *         that name.
051     */
052    NamedFilterList getChain(String chainName);
053
054    /**
055     * Returns {@code true} if one or more configured chains are available, {@code false} if none are configured.
056     *
057     * @return {@code true} if one or more configured chains are available, {@code false} if none are configured.
058     */
059    boolean hasChains();
060
061    /**
062     * Returns the names of all configured chains or an empty {@code Set} if no chains have been configured.
063     *
064     * @return the names of all configured chains or an empty {@code Set} if no chains have been configured.
065     */
066    Set<String> getChainNames();
067
068    /**
069     * Proxies the specified {@code original} FilterChain with the named chain.  The returned
070     * {@code FilterChain} instance will first execute the configured named chain and then lastly invoke the given
071     * {@code original} chain.
072     *
073     * @param original  the original FilterChain to proxy
074     * @param chainName the name of the internal configured filter chain that should 'sit in front' of the specified
075     *                  original chain.
076     * @return a {@code FilterChain} instance that will execute the named chain and then finally the
077     *         specified {@code original} FilterChain instance.
078     * @throws IllegalArgumentException if there is no configured chain with the given {@code chainName}.
079     */
080    FilterChain proxy(FilterChain original, String chainName);
081
082    /**
083     * Adds a filter to the 'pool' of available filters that can be used when
084     * {@link #addToChain(String, String, String) creating filter chains}.
085     * <p/>
086     * Calling this method is effectively the same as calling
087     * <code>{@link #addFilter(String, javax.servlet.Filter, boolean) addFilter}(name, filter, <b>false</b>);</code>
088     *
089     * @param name   the name to assign to the filter, used to reference the filter in chain definitions
090     * @param filter the filter to initialize and then add to the pool of available filters that can be used
091     */
092    void addFilter(String name, Filter filter);
093
094    /**
095     * Adds a filter to the 'pool' of available filters that can be used when
096     * {@link #addToChain(String, String, String) creating filter chains}.
097     *
098     * @param name   the name to assign to the filter, used to reference the filter in chain definitions
099     * @param filter the filter to assign to the filter pool
100     * @param init   whether or not the {@code Filter} should be
101     *               {@link Filter#init(javax.servlet.FilterConfig) initialized} first before being added to the pool.
102     */
103    void addFilter(String name, Filter filter, boolean init);
104
105    /**
106     * Creates a filter chain for the given {@code chainName} with the specified {@code chainDefinition}
107     * String.
108     * <h3>Conventional Use</h3>
109     * Because the {@code FilterChainManager} interface does not impose any restrictions on filter chain names,
110     * (it expects only Strings), a convenient convention is to make the chain name an actual URL path expression
111     * (such as an {@link org.apache.shiro.util.AntPathMatcher Ant path expression}).  For example:
112     * <p/>
113     * <code>createChain(<b><em>path_expression</em></b>, <em>path_specific_filter_chain_definition</em>);</code>
114     * This convention can be used by a {@link FilterChainResolver} to inspect request URL paths
115     * against the chain name (path) and, if a match is found, return the corresponding chain for runtime filtering.
116     * <h3>Chain Definition Format</h3>
117     * The {@code chainDefinition} method argument is expected to conform to the following format:
118     * <pre>
119     * filter1[optional_config1], filter2[optional_config2], ..., filterN[optional_configN]</pre>
120     * where
121     * <ol>
122     * <li>{@code filterN} is the name of a filter previously
123     * {@link #addFilter(String, javax.servlet.Filter) registered} with the manager, and</li>
124     * <li>{@code [optional_configN]} is an optional bracketed string that has meaning for that particular filter for
125     * <em>this particular chain</em></li>
126     * </ol>
127     * If the filter does not need specific config for that chain name/URL path,
128     * you may discard the brackets - that is, {@code filterN[]} just becomes {@code filterN}.
129     * <p/>
130     * And because this method does create a chain, remember that order matters!  The comma-delimited filter tokens in
131     * the {@code chainDefinition} specify the chain's execution order.
132     * <h3>Examples</h3>
133     * <pre>/account/** = authcBasic</pre>
134     * This example says &quot;Create a filter named '{@code /account/**}' consisting of only the '{@code authcBasic}'
135     * filter&quot;.  Also because the {@code authcBasic} filter does not need any path-specific
136     * config, it doesn't have any config brackets {@code []}.
137     * <p/>
138     * <pre>/remoting/** = authcBasic, roles[b2bClient], perms[&quot;remote:invoke:wan,lan&quot;]</pre>
139     * This example by contrast uses the 'roles' and 'perms' filters which <em>do</em> use bracket notation.  This
140     * definition says:
141     * <p/>
142     * Construct a filter chain named '{@code /remoting/**}' which
143     * <ol>
144     * <li>ensures the user is first authenticated ({@code authcBasic}) then</li>
145     * <li>ensures that user has the {@code b2bClient} role, and then finally</li>
146     * <li>ensures that they have the {@code remote:invoke:lan,wan} permission.</li>
147     * </ol>
148     * <p/>
149     * <b>Note</b>: because elements within brackets [ ] can be comma-delimited themselves, you must quote the
150     * internal bracket definition if commas are needed (the above example has 'lan,wan').  If we didn't do that, the
151     * parser would interpret the chain definition as four tokens:
152     * <ol>
153     * <li>authcBasic</li>
154     * <li>roles[b2bclient]</li>
155     * <li>perms[remote:invoke:lan</li>
156     * <li>wan]</li>
157     * </ol>
158     * which is obviously incorrect.  So remember to use quotes if your internal bracket definitions need to use commas.
159     *
160     * @param chainName       the name to associate with the chain, conventionally a URL path pattern.
161     * @param chainDefinition the string-formatted chain definition used to construct an actual
162     *                        {@link NamedFilterList} chain instance.
163     * @see FilterChainResolver
164     * @see org.apache.shiro.util.AntPathMatcher AntPathMatcher
165     */
166    void createChain(String chainName, String chainDefinition);
167
168    /**
169     * Creates a chain that should match any non-matched request paths, typically {@code /**} assuming an {@link AntPathMatcher} I used.
170     * @param chainName The name of the chain to create, likely {@code /**}.
171     * @since 1.6
172     * @see org.apache.shiro.lang.util.AntPathMatcher AntPathMatcher
173     */
174    void createDefaultChain(String chainName);
175
176    /**
177     * Adds (appends) a filter to the filter chain identified by the given {@code chainName}.  If there is no chain
178     * with the given name, a new one is created and the filter will be the first in the chain.
179     *
180     * @param chainName  the name of the chain where the filter will be appended.
181     * @param filterName the name of the {@link #addFilter registered} filter to add to the chain.
182     * @throws IllegalArgumentException if there is not a {@link #addFilter(String, javax.servlet.Filter) registered}
183     *                                  filter under the given {@code filterName}
184     */
185    void addToChain(String chainName, String filterName);
186
187    /**
188     * Adds (appends) a filter to the filter chain identified by the given {@code chainName}.  If there is no chain
189     * with the given name, a new one is created and the filter will be the first in the chain.
190     * <p/>
191     * Note that the final argument expects the associated filter to be an instance of
192     * a {@link org.apache.shiro.web.filter.PathConfigProcessor PathConfigProcessor} to accept per-chain configuration.
193     * If it is not, a {@link IllegalArgumentException} will be thrown.
194     *
195     * @param chainName                 the name of the chain where the filter will be appended.
196     * @param filterName                the name of the {@link #addFilter registered} filter to add to the chain.
197     * @param chainSpecificFilterConfig the filter-specific configuration that should be applied for only the specified
198     *                                  filter chain.
199     * @throws IllegalArgumentException if there is not a {@link #addFilter(String, javax.servlet.Filter) registered}
200     *                                  filter under the given {@code filterName}
201     * @throws ConfigurationException   if the filter is not capable of accepting {@code chainSpecificFilterConfig}
202     *                                  (usually such filters implement the
203     *                                  {@link org.apache.shiro.web.filter.PathConfigProcessor PathConfigProcessor}
204     *                                  interface).
205     */
206    void addToChain(String chainName, String filterName, String chainSpecificFilterConfig) throws ConfigurationException;
207
208    /**
209     * Configures the set of named filters that will match all paths.  These filters will match BEFORE explicitly
210     * configured filter chains i.e. by calling {@link #createChain(String, String)}, {@link #addToChain(String, String)}, etc.
211     * <br>
212     * <strong>Filters configured in this list wll apply to ALL requests.</strong>
213     *
214     * @param globalFilterNames         the list of filter names to match ALL paths.
215     * @throws ConfigurationException   if one of the filter names is invalid and cannot be loaded from the set of
216     *                                  configured filters {@link #getFilters()}}.
217     * @since 1.6
218     */
219    void setGlobalFilters(List<String> globalFilterNames) throws ConfigurationException;
220}