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.config; 020 021import org.apache.shiro.config.Ini; 022import org.apache.shiro.ini.IniFactorySupport; 023import org.apache.shiro.ini.IniSecurityManagerFactory; 024import org.apache.shiro.config.ogdl.ReflectionBuilder; 025import org.apache.shiro.util.CollectionUtils; 026import org.apache.shiro.lang.util.Factory; 027import org.apache.shiro.web.filter.mgt.DefaultFilter; 028import org.apache.shiro.web.filter.mgt.FilterChainManager; 029import org.apache.shiro.web.filter.mgt.FilterChainResolver; 030import org.apache.shiro.web.filter.mgt.PathMatchingFilterChainResolver; 031import org.slf4j.Logger; 032import org.slf4j.LoggerFactory; 033 034import javax.servlet.Filter; 035import javax.servlet.FilterConfig; 036import java.util.Collections; 037import java.util.LinkedHashMap; 038import java.util.List; 039import java.util.Map; 040 041/** 042 * A {@link Factory} that creates {@link FilterChainResolver} instances based on {@link Ini} configuration. 043 * 044 * @since 1.0 045 */ 046@SuppressWarnings("deprecation") 047public class IniFilterChainResolverFactory extends IniFactorySupport<FilterChainResolver> { 048 049 /** 050 * filters key. 051 */ 052 public static final String FILTERS = "filters"; 053 /** 054 * urls key. 055 */ 056 public static final String URLS = "urls"; 057 058 private static final Logger LOGGER = LoggerFactory.getLogger(IniFilterChainResolverFactory.class); 059 060 private FilterConfig filterConfig; 061 062 private List<String> globalFilters = Collections.singletonList(DefaultFilter.invalidRequest.name()); 063 064 public IniFilterChainResolverFactory() { 065 super(); 066 } 067 068 public IniFilterChainResolverFactory(Ini ini) { 069 super(ini); 070 } 071 072 public IniFilterChainResolverFactory(Ini ini, Map<String, ?> defaultBeans) { 073 this(ini); 074 this.setDefaults(defaultBeans); 075 } 076 077 public FilterConfig getFilterConfig() { 078 return filterConfig; 079 } 080 081 public void setFilterConfig(FilterConfig filterConfig) { 082 this.filterConfig = filterConfig; 083 } 084 085 public List<String> getGlobalFilters() { 086 return globalFilters; 087 } 088 089 public void setGlobalFilters(List<String> globalFilters) { 090 this.globalFilters = globalFilters; 091 } 092 093 protected FilterChainResolver createInstance(Ini ini) { 094 FilterChainResolver filterChainResolver = createDefaultInstance(); 095 if (filterChainResolver instanceof PathMatchingFilterChainResolver) { 096 PathMatchingFilterChainResolver resolver = (PathMatchingFilterChainResolver) filterChainResolver; 097 FilterChainManager manager = resolver.getFilterChainManager(); 098 buildChains(manager, ini); 099 } 100 return filterChainResolver; 101 } 102 103 protected FilterChainResolver createDefaultInstance() { 104 FilterConfig filterConfig = getFilterConfig(); 105 if (filterConfig != null) { 106 return new PathMatchingFilterChainResolver(filterConfig); 107 } else { 108 return new PathMatchingFilterChainResolver(); 109 } 110 } 111 112 protected void buildChains(FilterChainManager manager, Ini ini) { 113 //filters section: 114 Ini.Section section = ini.getSection(FILTERS); 115 116 if (!CollectionUtils.isEmpty(section)) { 117 String msg = "The [{}] section has been deprecated and will be removed in a future release! Please " 118 + "move all object configuration (filters and all other objects) to the [{}] section."; 119 LOGGER.warn(msg, FILTERS, IniSecurityManagerFactory.MAIN_SECTION_NAME); 120 } 121 122 Map<String, Object> defaults = new LinkedHashMap<String, Object>(); 123 124 Map<String, Filter> defaultFilters = manager.getFilters(); 125 126 //now let's see if there are any object defaults in addition to the filters 127 //these can be used to configure the filters: 128 //create a Map of objects to use as the defaults: 129 if (!CollectionUtils.isEmpty(defaultFilters)) { 130 defaults.putAll(defaultFilters); 131 } 132 //User-provided objects must come _after_ the default filters - to allow the user-provided 133 //ones to override the default filters if necessary. 134 Map<String, ?> defaultBeans = getDefaults(); 135 if (!CollectionUtils.isEmpty(defaultBeans)) { 136 defaults.putAll(defaultBeans); 137 } 138 139 Map<String, Filter> filters = getFilters(section, defaults); 140 141 //add the filters to the manager: 142 registerFilters(filters, manager); 143 144 manager.setGlobalFilters(getGlobalFilters()); 145 146 //urls section: 147 section = ini.getSection(URLS); 148 createChains(section, manager); 149 150 // create the default chain, to match anything the path matching would have missed 151 // TODO this assumes ANT path matching 152 manager.createDefaultChain("/**"); 153 } 154 155 protected void registerFilters(Map<String, Filter> filters, FilterChainManager manager) { 156 if (!CollectionUtils.isEmpty(filters)) { 157 //only call filter.init if there is a FilterConfig available 158 boolean init = getFilterConfig() != null; 159 for (Map.Entry<String, Filter> entry : filters.entrySet()) { 160 String name = entry.getKey(); 161 Filter filter = entry.getValue(); 162 manager.addFilter(name, filter, init); 163 } 164 } 165 } 166 167 protected Map<String, Filter> getFilters(Map<String, String> section, Map<String, ?> defaults) { 168 169 Map<String, Filter> filters = extractFilters(defaults); 170 171 if (!CollectionUtils.isEmpty(section)) { 172 ReflectionBuilder builder = new ReflectionBuilder(defaults); 173 Map<String, ?> built = builder.buildObjects(section); 174 Map<String, Filter> sectionFilters = extractFilters(built); 175 176 if (CollectionUtils.isEmpty(filters)) { 177 filters = sectionFilters; 178 } else { 179 if (!CollectionUtils.isEmpty(sectionFilters)) { 180 filters.putAll(sectionFilters); 181 } 182 } 183 } 184 185 return filters; 186 } 187 188 private Map<String, Filter> extractFilters(Map<String, ?> objects) { 189 if (CollectionUtils.isEmpty(objects)) { 190 return null; 191 } 192 Map<String, Filter> filterMap = new LinkedHashMap<String, Filter>(); 193 for (Map.Entry<String, ?> entry : objects.entrySet()) { 194 String key = entry.getKey(); 195 Object value = entry.getValue(); 196 if (value instanceof Filter) { 197 filterMap.put(key, (Filter) value); 198 } 199 } 200 return filterMap; 201 } 202 203 protected void createChains(Map<String, String> urls, FilterChainManager manager) { 204 if (CollectionUtils.isEmpty(urls)) { 205 if (LOGGER.isDebugEnabled()) { 206 LOGGER.debug("No urls to process."); 207 } 208 return; 209 } 210 211 if (LOGGER.isTraceEnabled()) { 212 LOGGER.trace("Before url processing."); 213 } 214 215 for (Map.Entry<String, String> entry : urls.entrySet()) { 216 String path = entry.getKey(); 217 String value = entry.getValue(); 218 manager.createChain(path, value); 219 } 220 } 221}