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