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.FilterChainManager;
28  import org.apache.shiro.web.filter.mgt.FilterChainResolver;
29  import org.apache.shiro.web.filter.mgt.PathMatchingFilterChainResolver;
30  import org.slf4j.Logger;
31  import org.slf4j.LoggerFactory;
32  
33  import javax.servlet.Filter;
34  import javax.servlet.FilterConfig;
35  import java.util.LinkedHashMap;
36  import java.util.Map;
37  
38  /**
39   * A {@link Factory} that creates {@link FilterChainResolver} instances based on {@link Ini} configuration.
40   *
41   * @since 1.0
42   */
43  public class IniFilterChainResolverFactory extends IniFactorySupport<FilterChainResolver> {
44  
45      public static final String FILTERS = "filters";
46      public static final String URLS = "urls";
47  
48      private static transient final Logger log = LoggerFactory.getLogger(IniFilterChainResolverFactory.class);
49  
50      private FilterConfig filterConfig;
51  
52      public IniFilterChainResolverFactory() {
53          super();
54      }
55  
56      public IniFilterChainResolverFactory(Ini ini) {
57          super(ini);
58      }
59  
60      public IniFilterChainResolverFactory(Ini ini, Map<String, ?> defaultBeans) {
61          this(ini);
62          this.setDefaults(defaultBeans);
63      }
64  
65      public FilterConfig getFilterConfig() {
66          return filterConfig;
67      }
68  
69      public void setFilterConfig(FilterConfig filterConfig) {
70          this.filterConfig = filterConfig;
71      }
72  
73      protected FilterChainResolver createInstance(Ini ini) {
74          FilterChainResolver filterChainResolver = createDefaultInstance();
75          if (filterChainResolver instanceof PathMatchingFilterChainResolver) {
76              PathMatchingFilterChainResolverhiro/web/filter/mgt/PathMatchingFilterChainResolver.html#PathMatchingFilterChainResolver">PathMatchingFilterChainResolver resolver = (PathMatchingFilterChainResolver) filterChainResolver;
77              FilterChainManager manager = resolver.getFilterChainManager();
78              buildChains(manager, ini);
79          }
80          return filterChainResolver;
81      }
82  
83      protected FilterChainResolver createDefaultInstance() {
84          FilterConfig filterConfig = getFilterConfig();
85          if (filterConfig != null) {
86              return new PathMatchingFilterChainResolver(filterConfig);
87          } else {
88              return new PathMatchingFilterChainResolver();
89          }
90      }
91  
92      protected void buildChains(FilterChainManager manager, Ini ini) {
93          //filters section:
94          Ini.Section section = ini.getSection(FILTERS);
95  
96          if (!CollectionUtils.isEmpty(section)) {
97              String msg = "The [{}] section has been deprecated and will be removed in a future release!  Please " +
98                      "move all object configuration (filters and all other objects) to the [{}] section.";
99              log.warn(msg, FILTERS, IniSecurityManagerFactory.MAIN_SECTION_NAME);
100         }
101 
102         Map<String, Object> defaults = new LinkedHashMap<String, Object>();
103 
104         Map<String, Filter> defaultFilters = manager.getFilters();
105 
106         //now let's see if there are any object defaults in addition to the filters
107         //these can be used to configure the filters:
108         //create a Map of objects to use as the defaults:
109         if (!CollectionUtils.isEmpty(defaultFilters)) {
110             defaults.putAll(defaultFilters);
111         }
112         //User-provided objects must come _after_ the default filters - to allow the user-provided
113         //ones to override the default filters if necessary.
114         Map<String, ?> defaultBeans = getDefaults();
115         if (!CollectionUtils.isEmpty(defaultBeans)) {
116             defaults.putAll(defaultBeans);
117         }
118 
119         Map<String, Filter> filters = getFilters(section, defaults);
120 
121         //add the filters to the manager:
122         registerFilters(filters, manager);
123 
124         //urls section:
125         section = ini.getSection(URLS);
126         createChains(section, manager);
127     }
128 
129     protected void registerFilters(Map<String, Filter> filters, FilterChainManager manager) {
130         if (!CollectionUtils.isEmpty(filters)) {
131             boolean init = getFilterConfig() != null; //only call filter.init if there is a FilterConfig available
132             for (Map.Entry<String, Filter> entry : filters.entrySet()) {
133                 String name = entry.getKey();
134                 Filter filter = entry.getValue();
135                 manager.addFilter(name, filter, init);
136             }
137         }
138     }
139 
140     protected Map<String, Filter> getFilters(Map<String, String> section, Map<String, ?> defaults) {
141 
142         Map<String, Filter> filters = extractFilters(defaults);
143 
144         if (!CollectionUtils.isEmpty(section)) {
145             ReflectionBuilder builder = new ReflectionBuilder(defaults);
146             Map<String, ?> built = builder.buildObjects(section);
147             Map<String,Filter> sectionFilters = extractFilters(built);
148 
149             if (CollectionUtils.isEmpty(filters)) {
150                 filters = sectionFilters;
151             } else {
152                 if (!CollectionUtils.isEmpty(sectionFilters)) {
153                     filters.putAll(sectionFilters);
154                 }
155             }
156         }
157 
158         return filters;
159     }
160 
161     private Map<String, Filter> extractFilters(Map<String, ?> objects) {
162         if (CollectionUtils.isEmpty(objects)) {
163             return null;
164         }
165         Map<String, Filter> filterMap = new LinkedHashMap<String, Filter>();
166         for (Map.Entry<String, ?> entry : objects.entrySet()) {
167             String key = entry.getKey();
168             Object value = entry.getValue();
169             if (value instanceof Filter) {
170                 filterMap.put(key, (Filter) value);
171             }
172         }
173         return filterMap;
174     }
175 
176     protected void createChains(Map<String, String> urls, FilterChainManager manager) {
177         if (CollectionUtils.isEmpty(urls)) {
178             if (log.isDebugEnabled()) {
179                 log.debug("No urls to process.");
180             }
181             return;
182         }
183 
184         if (log.isTraceEnabled()) {
185             log.trace("Before url processing.");
186         }
187 
188         for (Map.Entry<String, String> entry : urls.entrySet()) {
189             String path = entry.getKey();
190             String value = entry.getValue();
191             manager.createChain(path, value);
192         }
193     }
194 }