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 */
019 package org.apache.shiro.web.config;
020
021 import org.apache.shiro.config.Ini;
022 import org.apache.shiro.config.IniFactorySupport;
023 import org.apache.shiro.config.IniSecurityManagerFactory;
024 import org.apache.shiro.config.ReflectionBuilder;
025 import org.apache.shiro.util.CollectionUtils;
026 import org.apache.shiro.util.Factory;
027 import org.apache.shiro.web.filter.mgt.FilterChainManager;
028 import org.apache.shiro.web.filter.mgt.FilterChainResolver;
029 import org.apache.shiro.web.filter.mgt.PathMatchingFilterChainResolver;
030 import org.slf4j.Logger;
031 import org.slf4j.LoggerFactory;
032
033 import javax.servlet.Filter;
034 import javax.servlet.FilterConfig;
035 import java.util.LinkedHashMap;
036 import java.util.Map;
037
038 /**
039 * A {@link Factory} that creates {@link FilterChainResolver} instances based on {@link Ini} configuration.
040 *
041 * @since 1.0
042 */
043 public class IniFilterChainResolverFactory extends IniFactorySupport<FilterChainResolver> {
044
045 public static final String FILTERS = "filters";
046 public static final String URLS = "urls";
047
048 private static transient final Logger log = LoggerFactory.getLogger(IniFilterChainResolverFactory.class);
049
050 private FilterConfig filterConfig;
051
052 private Map<String, ?> defaultBeans;
053
054 public IniFilterChainResolverFactory() {
055 super();
056 }
057
058 public IniFilterChainResolverFactory(Ini ini) {
059 super(ini);
060 }
061
062 public IniFilterChainResolverFactory(Ini ini, Map<String, ?> defaultBeans) {
063 this(ini);
064 this.defaultBeans = defaultBeans;
065 }
066
067 public FilterConfig getFilterConfig() {
068 return filterConfig;
069 }
070
071 public void setFilterConfig(FilterConfig filterConfig) {
072 this.filterConfig = filterConfig;
073 }
074
075 protected FilterChainResolver createInstance(Ini ini) {
076 FilterChainResolver filterChainResolver = createDefaultInstance();
077 if (filterChainResolver instanceof PathMatchingFilterChainResolver) {
078 PathMatchingFilterChainResolver resolver = (PathMatchingFilterChainResolver) filterChainResolver;
079 FilterChainManager manager = resolver.getFilterChainManager();
080 buildChains(manager, ini);
081 }
082 return filterChainResolver;
083 }
084
085 protected FilterChainResolver createDefaultInstance() {
086 FilterConfig filterConfig = getFilterConfig();
087 if (filterConfig != null) {
088 return new PathMatchingFilterChainResolver(filterConfig);
089 } else {
090 return new PathMatchingFilterChainResolver();
091 }
092 }
093
094 protected void buildChains(FilterChainManager manager, Ini ini) {
095 //filters section:
096 Ini.Section section = ini.getSection(FILTERS);
097
098 if (!CollectionUtils.isEmpty(section)) {
099 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;
144
145 if (!CollectionUtils.isEmpty(section)) {
146 ReflectionBuilder builder = new ReflectionBuilder(defaults);
147 Map<String, ?> built = builder.buildObjects(section);
148 filters = extractFilters(built);
149 } else {
150 filters = extractFilters(defaults);
151 }
152
153 return filters;
154 }
155
156 private Map<String, Filter> extractFilters(Map<String, ?> objects) {
157 if (CollectionUtils.isEmpty(objects)) {
158 return null;
159 }
160 Map<String, Filter> filterMap = new LinkedHashMap<String, Filter>();
161 for (Map.Entry<String, ?> entry : objects.entrySet()) {
162 String key = entry.getKey();
163 Object value = entry.getValue();
164 if (value instanceof Filter) {
165 filterMap.put(key, (Filter) value);
166 }
167 }
168 return filterMap;
169 }
170
171 protected void createChains(Map<String, String> urls, FilterChainManager manager) {
172 if (CollectionUtils.isEmpty(urls)) {
173 if (log.isDebugEnabled()) {
174 log.debug("No urls to process.");
175 }
176 return;
177 }
178
179 if (log.isTraceEnabled()) {
180 log.trace("Before url processing.");
181 }
182
183 for (Map.Entry<String, String> entry : urls.entrySet()) {
184 String path = entry.getKey();
185 String value = entry.getValue();
186 manager.createChain(path, value);
187 }
188 }
189 }