blob: 7118164424742025af4ae9d1c28e7d5942b01e46 [file] [log] [blame]
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
package org.apache.shiro.web.config;
import org.apache.shiro.config.Ini;
import org.apache.shiro.config.IniFactorySupport;
import org.apache.shiro.config.IniSecurityManagerFactory;
import org.apache.shiro.config.ReflectionBuilder;
import org.apache.shiro.util.CollectionUtils;
import org.apache.shiro.util.Factory;
import org.apache.shiro.web.filter.mgt.DefaultFilter;
import org.apache.shiro.web.filter.mgt.FilterChainManager;
import org.apache.shiro.web.filter.mgt.FilterChainResolver;
import org.apache.shiro.web.filter.mgt.PathMatchingFilterChainResolver;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import javax.servlet.Filter;
import javax.servlet.FilterConfig;
import java.util.Collections;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
/**
* A {@link Factory} that creates {@link FilterChainResolver} instances based on {@link Ini} configuration.
*
* @since 1.0
*/
public class IniFilterChainResolverFactory extends IniFactorySupport<FilterChainResolver> {
public static final String FILTERS = "filters";
public static final String URLS = "urls";
private static transient final Logger log = LoggerFactory.getLogger(IniFilterChainResolverFactory.class);
private FilterConfig filterConfig;
private List<String> globalFilters = Collections.singletonList(DefaultFilter.invalidRequest.name());
public IniFilterChainResolverFactory() {
super();
}
public IniFilterChainResolverFactory(Ini ini) {
super(ini);
}
public IniFilterChainResolverFactory(Ini ini, Map<String, ?> defaultBeans) {
this(ini);
this.setDefaults(defaultBeans);
}
public FilterConfig getFilterConfig() {
return filterConfig;
}
public void setFilterConfig(FilterConfig filterConfig) {
this.filterConfig = filterConfig;
}
public List<String> getGlobalFilters() {
return globalFilters;
}
public void setGlobalFilters(List<String> globalFilters) {
this.globalFilters = globalFilters;
}
protected FilterChainResolver createInstance(Ini ini) {
FilterChainResolver filterChainResolver = createDefaultInstance();
if (filterChainResolver instanceof PathMatchingFilterChainResolver) {
PathMatchingFilterChainResolver resolver = (PathMatchingFilterChainResolver) filterChainResolver;
FilterChainManager manager = resolver.getFilterChainManager();
buildChains(manager, ini);
}
return filterChainResolver;
}
protected FilterChainResolver createDefaultInstance() {
FilterConfig filterConfig = getFilterConfig();
if (filterConfig != null) {
return new PathMatchingFilterChainResolver(filterConfig);
} else {
return new PathMatchingFilterChainResolver();
}
}
protected void buildChains(FilterChainManager manager, Ini ini) {
//filters section:
Ini.Section section = ini.getSection(FILTERS);
if (!CollectionUtils.isEmpty(section)) {
String msg = "The [{}] section has been deprecated and will be removed in a future release! Please " +
"move all object configuration (filters and all other objects) to the [{}] section.";
log.warn(msg, FILTERS, IniSecurityManagerFactory.MAIN_SECTION_NAME);
}
Map<String, Object> defaults = new LinkedHashMap<String, Object>();
Map<String, Filter> defaultFilters = manager.getFilters();
//now let's see if there are any object defaults in addition to the filters
//these can be used to configure the filters:
//create a Map of objects to use as the defaults:
if (!CollectionUtils.isEmpty(defaultFilters)) {
defaults.putAll(defaultFilters);
}
//User-provided objects must come _after_ the default filters - to allow the user-provided
//ones to override the default filters if necessary.
Map<String, ?> defaultBeans = getDefaults();
if (!CollectionUtils.isEmpty(defaultBeans)) {
defaults.putAll(defaultBeans);
}
Map<String, Filter> filters = getFilters(section, defaults);
//add the filters to the manager:
registerFilters(filters, manager);
manager.setGlobalFilters(getGlobalFilters());
//urls section:
section = ini.getSection(URLS);
createChains(section, manager);
// create the default chain, to match anything the path matching would have missed
manager.createDefaultChain("/**"); // TODO this assumes ANT path matching
}
protected void registerFilters(Map<String, Filter> filters, FilterChainManager manager) {
if (!CollectionUtils.isEmpty(filters)) {
boolean init = getFilterConfig() != null; //only call filter.init if there is a FilterConfig available
for (Map.Entry<String, Filter> entry : filters.entrySet()) {
String name = entry.getKey();
Filter filter = entry.getValue();
manager.addFilter(name, filter, init);
}
}
}
protected Map<String, Filter> getFilters(Map<String, String> section, Map<String, ?> defaults) {
Map<String, Filter> filters = extractFilters(defaults);
if (!CollectionUtils.isEmpty(section)) {
ReflectionBuilder builder = new ReflectionBuilder(defaults);
Map<String, ?> built = builder.buildObjects(section);
Map<String,Filter> sectionFilters = extractFilters(built);
if (CollectionUtils.isEmpty(filters)) {
filters = sectionFilters;
} else {
if (!CollectionUtils.isEmpty(sectionFilters)) {
filters.putAll(sectionFilters);
}
}
}
return filters;
}
private Map<String, Filter> extractFilters(Map<String, ?> objects) {
if (CollectionUtils.isEmpty(objects)) {
return null;
}
Map<String, Filter> filterMap = new LinkedHashMap<String, Filter>();
for (Map.Entry<String, ?> entry : objects.entrySet()) {
String key = entry.getKey();
Object value = entry.getValue();
if (value instanceof Filter) {
filterMap.put(key, (Filter) value);
}
}
return filterMap;
}
protected void createChains(Map<String, String> urls, FilterChainManager manager) {
if (CollectionUtils.isEmpty(urls)) {
if (log.isDebugEnabled()) {
log.debug("No urls to process.");
}
return;
}
if (log.isTraceEnabled()) {
log.trace("Before url processing.");
}
for (Map.Entry<String, String> entry : urls.entrySet()) {
String path = entry.getKey();
String value = entry.getValue();
manager.createChain(path, value);
}
}
}