View Javadoc
1   /*
2    * Licensed to the Apache Software Foundation (ASF) under one
3    * or more contributor license agreements.  See the NOTICE file
4    * distributed with this work for additional information
5    * regarding copyright ownership.  The ASF licenses this file
6    * to you under the Apache License, Version 2.0 (the
7    * "License"); you may not use this file except in compliance
8    * with the License.  You may obtain a copy of the License at
9    *
10   *     http://www.apache.org/licenses/LICENSE-2.0
11   *
12   * Unless required by applicable law or agreed to in writing,
13   * software distributed under the License is distributed on an
14   * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
15   * KIND, either express or implied.  See the License for the
16   * specific language governing permissions and limitations
17   * under the License.
18   */
19  package org.apache.shiro.web.config;
20  
21  import org.apache.shiro.config.Ini;
22  import org.apache.shiro.config.IniFactorySupport;
23  import org.apache.shiro.config.IniSecurityManagerFactory;
24  import org.apache.shiro.config.ReflectionBuilder;
25  import org.apache.shiro.util.CollectionUtils;
26  import org.apache.shiro.util.Factory;
27  import org.apache.shiro.web.filter.mgt.DefaultFilter;
28  import org.apache.shiro.web.filter.mgt.FilterChainManager;
29  import org.apache.shiro.web.filter.mgt.FilterChainResolver;
30  import org.apache.shiro.web.filter.mgt.PathMatchingFilterChainResolver;
31  import org.slf4j.Logger;
32  import org.slf4j.LoggerFactory;
33  
34  import javax.servlet.Filter;
35  import javax.servlet.FilterConfig;
36  import java.util.Collections;
37  import java.util.LinkedHashMap;
38  import java.util.List;
39  import java.util.Map;
40  
41  /**
42   * A {@link Factory} that creates {@link FilterChainResolver} instances based on {@link Ini} configuration.
43   *
44   * @since 1.0
45   */
46  public class IniFilterChainResolverFactory extends IniFactorySupport<FilterChainResolver> {
47  
48      public static final String FILTERS = "filters";
49      public static final String URLS = "urls";
50  
51      private static transient final Logger log = LoggerFactory.getLogger(IniFilterChainResolverFactory.class);
52  
53      private FilterConfig filterConfig;
54  
55      private List<String> globalFilters = Collections.singletonList(DefaultFilter.invalidRequest.name());
56  
57      public IniFilterChainResolverFactory() {
58          super();
59      }
60  
61      public IniFilterChainResolverFactory(Ini ini) {
62          super(ini);
63      }
64  
65      public IniFilterChainResolverFactory(Ini ini, Map<String, ?> defaultBeans) {
66          this(ini);
67          this.setDefaults(defaultBeans);
68      }
69  
70      public FilterConfig getFilterConfig() {
71          return filterConfig;
72      }
73  
74      public void setFilterConfig(FilterConfig filterConfig) {
75          this.filterConfig = filterConfig;
76      }
77  
78      public List<String> getGlobalFilters() {
79          return globalFilters;
80      }
81  
82      public void setGlobalFilters(List<String> globalFilters) {
83          this.globalFilters = globalFilters;
84      }
85  
86      protected FilterChainResolver createInstance(Ini ini) {
87          FilterChainResolver filterChainResolver = createDefaultInstance();
88          if (filterChainResolver instanceof PathMatchingFilterChainResolver) {
89              PathMatchingFilterChainResolverhiro/web/filter/mgt/PathMatchingFilterChainResolver.html#PathMatchingFilterChainResolver">PathMatchingFilterChainResolver resolver = (PathMatchingFilterChainResolver) filterChainResolver;
90              FilterChainManager manager = resolver.getFilterChainManager();
91              buildChains(manager, ini);
92          }
93          return filterChainResolver;
94      }
95  
96      protected FilterChainResolver createDefaultInstance() {
97          FilterConfig filterConfig = getFilterConfig();
98          if (filterConfig != null) {
99              return new PathMatchingFilterChainResolver(filterConfig);
100         } else {
101             return new PathMatchingFilterChainResolver();
102         }
103     }
104 
105     protected void buildChains(FilterChainManager manager, Ini ini) {
106         //filters section:
107         Ini.Section section = ini.getSection(FILTERS);
108 
109         if (!CollectionUtils.isEmpty(section)) {
110             String msg = "The [{}] section has been deprecated and will be removed in a future release!  Please " +
111                     "move all object configuration (filters and all other objects) to the [{}] section.";
112             log.warn(msg, FILTERS, IniSecurityManagerFactory.MAIN_SECTION_NAME);
113         }
114 
115         Map<String, Object> defaults = new LinkedHashMap<String, Object>();
116 
117         Map<String, Filter> defaultFilters = manager.getFilters();
118 
119         //now let's see if there are any object defaults in addition to the filters
120         //these can be used to configure the filters:
121         //create a Map of objects to use as the defaults:
122         if (!CollectionUtils.isEmpty(defaultFilters)) {
123             defaults.putAll(defaultFilters);
124         }
125         //User-provided objects must come _after_ the default filters - to allow the user-provided
126         //ones to override the default filters if necessary.
127         Map<String, ?> defaultBeans = getDefaults();
128         if (!CollectionUtils.isEmpty(defaultBeans)) {
129             defaults.putAll(defaultBeans);
130         }
131 
132         Map<String, Filter> filters = getFilters(section, defaults);
133 
134         //add the filters to the manager:
135         registerFilters(filters, manager);
136 
137         manager.setGlobalFilters(getGlobalFilters());
138 
139         //urls section:
140         section = ini.getSection(URLS);
141         createChains(section, manager);
142 
143         // create the default chain, to match anything the path matching would have missed
144         manager.createDefaultChain("/**"); // TODO this assumes ANT path matching
145     }
146 
147     protected void registerFilters(Map<String, Filter> filters, FilterChainManager manager) {
148         if (!CollectionUtils.isEmpty(filters)) {
149             boolean init = getFilterConfig() != null; //only call filter.init if there is a FilterConfig available
150             for (Map.Entry<String, Filter> entry : filters.entrySet()) {
151                 String name = entry.getKey();
152                 Filter filter = entry.getValue();
153                 manager.addFilter(name, filter, init);
154             }
155         }
156     }
157 
158     protected Map<String, Filter> getFilters(Map<String, String> section, Map<String, ?> defaults) {
159 
160         Map<String, Filter> filters = extractFilters(defaults);
161 
162         if (!CollectionUtils.isEmpty(section)) {
163             ReflectionBuilderlder.html#ReflectionBuilder">ReflectionBuilder builder = new ReflectionBuilder(defaults);
164             Map<String, ?> built = builder.buildObjects(section);
165             Map<String,Filter> sectionFilters = extractFilters(built);
166 
167             if (CollectionUtils.isEmpty(filters)) {
168                 filters = sectionFilters;
169             } else {
170                 if (!CollectionUtils.isEmpty(sectionFilters)) {
171                     filters.putAll(sectionFilters);
172                 }
173             }
174         }
175 
176         return filters;
177     }
178 
179     private Map<String, Filter> extractFilters(Map<String, ?> objects) {
180         if (CollectionUtils.isEmpty(objects)) {
181             return null;
182         }
183         Map<String, Filter> filterMap = new LinkedHashMap<String, Filter>();
184         for (Map.Entry<String, ?> entry : objects.entrySet()) {
185             String key = entry.getKey();
186             Object value = entry.getValue();
187             if (value instanceof Filter) {
188                 filterMap.put(key, (Filter) value);
189             }
190         }
191         return filterMap;
192     }
193 
194     protected void createChains(Map<String, String> urls, FilterChainManager manager) {
195         if (CollectionUtils.isEmpty(urls)) {
196             if (log.isDebugEnabled()) {
197                 log.debug("No urls to process.");
198             }
199             return;
200         }
201 
202         if (log.isTraceEnabled()) {
203             log.trace("Before url processing.");
204         }
205 
206         for (Map.Entry<String, String> entry : urls.entrySet()) {
207             String path = entry.getKey();
208             String value = entry.getValue();
209             manager.createChain(path, value);
210         }
211     }
212 }