/* (c) 2014 Open Source Geospatial Foundation - all rights reserved * (c) 2001 - 2013 OpenPlans * This code is licensed under the GPL 2.0 license, available at the root * application directory. */ package org.geoserver.security; import java.io.Serializable; import java.util.ArrayList; import java.util.Collections; import java.util.List; /** * The security filter filter chain. * <p> * The content of {code antPatterns} must be equal to the keys of {code filterMap}. * # * </p> * <p> * The order of {code antPatterns} determines the order of ant pattern matching used by * GeoServerSecurityFilterChainProxy. * </p> * @author christian * */ public class GeoServerSecurityFilterChain implements Serializable { /** serialVersionUID */ private static final long serialVersionUID = 1L; List<RequestFilterChain> requestChains = new ArrayList<RequestFilterChain>(); /* * chain patterns */ public static final String WEB_CHAIN = "/web/**"; public static final String FORM_LOGIN_CHAIN = "/j_spring_security_check,/j_spring_security_check/,/login"; public static final String FORM_LOGOUT_CHAIN = "/j_spring_security_logout,/j_spring_security_logout/,/logout"; public static final String REST_CHAIN = "/rest/**"; public static final String GWC_WEB_CHAIN = "/gwc/rest/web/**"; public static final String GWC_REST_CHAIN = "/gwc/rest/**"; public static final String DEFAULT_CHAIN = "/**"; /* * filter names */ public static final String SECURITY_CONTEXT_ASC_FILTER = "contextAsc"; public static final String SECURITY_CONTEXT_NO_ASC_FILTER = "contextNoAsc"; public static final String ROLE_FILTER = "roleFilter"; public static final String SSL_FILTER = "sslFilter"; public static final String FORM_LOGIN_FILTER = "form"; public static final String FORM_LOGOUT_FILTER = "formLogout"; public static final String REMEMBER_ME_FILTER = "rememberme"; public static final String ANONYMOUS_FILTER = "anonymous"; public static final String BASIC_AUTH_FILTER = "basic"; //public static final String BASIC_AUTH_NO_REMEMBER_ME_FILTER = "basicAuthNrm"; public static final String DYNAMIC_EXCEPTION_TRANSLATION_FILTER = "exception"; public static final String GUI_EXCEPTION_TRANSLATION_FILTER = "guiException"; public static final String FILTER_SECURITY_INTERCEPTOR = "interceptor"; public static final String FILTER_SECURITY_REST_INTERCEPTOR = "restInterceptor"; // standard chain names as constant public static final String WEB_CHAIN_NAME="web"; public static final String WEB_LOGIN_CHAIN_NAME="webLogin"; public static final String WEB_LOGOUT_CHAIN_NAME="webLogout"; public static final String REST_CHAIN_NAME="rest"; public static final String GWC_CHAIN_NAME="gwc"; public static final String DEFAULT_CHAIN_NAME="default"; static HtmlLoginFilterChain WEB = new HtmlLoginFilterChain(WEB_CHAIN, GWC_WEB_CHAIN); static { WEB.setName(WEB_CHAIN_NAME); WEB.setFilterNames(REMEMBER_ME_FILTER, FORM_LOGIN_FILTER,ANONYMOUS_FILTER); WEB.setAllowSessionCreation(true); } private static ConstantFilterChain WEB_LOGIN = new ConstantFilterChain(FORM_LOGIN_CHAIN); static { WEB_LOGIN.setName(WEB_LOGIN_CHAIN_NAME); WEB_LOGIN.setFilterNames(FORM_LOGIN_FILTER); WEB_LOGIN.setAllowSessionCreation(true); } private static LogoutFilterChain WEB_LOGOUT = new LogoutFilterChain(FORM_LOGOUT_CHAIN); static { WEB_LOGOUT.setName(WEB_LOGOUT_CHAIN_NAME); WEB_LOGOUT.setFilterNames(FORM_LOGOUT_FILTER); } private static ServiceLoginFilterChain REST = new ServiceLoginFilterChain(REST_CHAIN); static { REST.setName(REST_CHAIN_NAME); REST.setFilterNames( BASIC_AUTH_FILTER, ANONYMOUS_FILTER); REST.setInterceptorName(FILTER_SECURITY_REST_INTERCEPTOR); } private static ServiceLoginFilterChain GWC = new ServiceLoginFilterChain(GWC_REST_CHAIN); static { GWC.setName(GWC_CHAIN_NAME); GWC.setFilterNames( BASIC_AUTH_FILTER); GWC.setInterceptorName(FILTER_SECURITY_REST_INTERCEPTOR); } private static ServiceLoginFilterChain DEFAULT = new ServiceLoginFilterChain(DEFAULT_CHAIN); static { DEFAULT.setName(DEFAULT_CHAIN_NAME); DEFAULT.setFilterNames( BASIC_AUTH_FILTER, ANONYMOUS_FILTER); } private static List<RequestFilterChain> INITIAL = new ArrayList<RequestFilterChain>(); static { INITIAL.add(WEB); INITIAL.add(WEB_LOGIN); INITIAL.add(WEB_LOGOUT); INITIAL.add(REST); INITIAL.add(GWC); INITIAL.add(DEFAULT); } public GeoServerSecurityFilterChain() { requestChains = new ArrayList<RequestFilterChain>(); } /** * Constructor cloning all collections */ public GeoServerSecurityFilterChain(List<RequestFilterChain> requestChains) { this.requestChains = requestChains; } /** * Constructor cloning all collections */ public GeoServerSecurityFilterChain(GeoServerSecurityFilterChain other) { this.requestChains = new ArrayList<RequestFilterChain>(other.getRequestChains()); } /** * Create the initial {@link GeoServerSecurityFilterChain} * * */ public static GeoServerSecurityFilterChain createInitialChain() { return new GeoServerSecurityFilterChain(new ArrayList<RequestFilterChain>(INITIAL)); } public void postConfigure(GeoServerSecurityManager secMgr) { // TODO, Justin // Not sure if this is correct, if it is, you can add the constant chain // for the root user login for(GeoServerSecurityProvider p : secMgr.lookupSecurityProviders()) { p.configureFilterChain(this); } } public static RequestFilterChain lookupRequestChainByName( String name, GeoServerSecurityManager secMgr) { //this is kind of a hack but we create an initial filter chain and run it through the // security provider extension points to get an actual final chain, and then look through // the elements for a matching name GeoServerSecurityFilterChain filterChain = createInitialChain(); filterChain.postConfigure(secMgr); for (RequestFilterChain requestChain : filterChain.getRequestChains()) { if (requestChain.getName().equals(name)) { return requestChain; } } return null; } public static RequestFilterChain lookupRequestChainByPattern( String pattern, GeoServerSecurityManager secMgr) { //this is kind of a hack but we create an initial filter chain and run it through the // security provider extension points to get an actual final chain, and then look through // the elements for a matching name GeoServerSecurityFilterChain filterChain = createInitialChain(); filterChain.postConfigure(secMgr); for (RequestFilterChain requestChain : filterChain.getRequestChains()) { if (requestChain.getPatterns().contains(pattern)) { return requestChain; } } return null; } public List<RequestFilterChain> getRequestChains() { return requestChains; } public List<RequestFilterChain> getVariableRequestChains() { List<RequestFilterChain> result = new ArrayList<RequestFilterChain>(); for (RequestFilterChain chain: getRequestChains()) if (chain.isConstant()==false) result.add(chain); return result; } public RequestFilterChain getRequestChainByName(String name) { for (RequestFilterChain requestChain : requestChains) { if (requestChain.getName().equals(name)) { return requestChain; } } return null; } /** * Inserts a filter as the first of the filter list corresponding to the specified pattern. * * @return True if the filter was inserted. */ public boolean insertFirst(String pattern, String filterName) { RequestFilterChain requestChain = findAndCheck(pattern, filterName); if (requestChain == null) { return false; } requestChain.getFilterNames().add(0, filterName); return false; } /** * Inserts a filter as the last of the filter list corresponding to the specified pattern. * * @return True if the filter was inserted. */ public boolean insertLast(String pattern, String filterName) { RequestFilterChain requestChain = findAndCheck(pattern, filterName); if (requestChain == null) { return false; } return requestChain.getFilterNames().add(filterName); } /** * Inserts a filter as before another in the list corresponding to the specified pattern. * * @return True if the filter was inserted. */ public boolean insertBefore(String pattern, String filterName, String positionName) { RequestFilterChain requestChain = findAndCheck(pattern, filterName); if (requestChain == null) { return false; } List<String> filterNames = requestChain.getFilterNames(); int index = filterNames.indexOf(positionName); if (index == -1) { return false; } filterNames.add(index, filterName); return true; } /** * Inserts a filter as after another in the list corresponding to the specified pattern. * * @return True if the filter was inserted. */ public boolean insertAfter(String pattern, String filterName, String positionName) { RequestFilterChain requestChain = findAndCheck(pattern, filterName); if (requestChain == null) { return false; } List<String> filterNames = requestChain.getFilterNames(); int index = filterNames.indexOf(positionName); if (index == -1) { return false; } filterNames.add(index+1,filterName); return true; } public RequestFilterChain find(String pattern) { return requestChain(pattern); } /** * Get a list of patterns having the filter in their chain. * If includeAll is false, only authentication filters are searched */ public List<String> patternsForFilter(String filterName, boolean includeAll) { List<String> result = new ArrayList<String>(); for (RequestFilterChain requestChain : requestChains) { List<String> filterNames = includeAll ? requestChain.getCompiledFilterNames() : requestChain.getFilterNames(); if (filterNames.contains(filterName)) { result.addAll(requestChain.getPatterns()); } } return result; } /** * Get the filters for the specified pattern. */ public List<String> filtersFor(String pattern) { RequestFilterChain requestChain = requestChain(pattern); if (requestChain == null) { return Collections.EMPTY_LIST; } return new ArrayList(requestChain.getFilterNames()); } public boolean removeForPattern(String pattern) { RequestFilterChain requestChain = requestChain(pattern); if (requestChain != null) { return requestChains.remove(requestChain); } return false; } /** * Removes a filter by name from all filter request chains. */ public boolean remove(String filterName) { boolean removed = false; for (RequestFilterChain requestChain : requestChains) { removed |= requestChain.getFilterNames().remove(filterName); } return removed; } RequestFilterChain findAndCheck(String pattern, String filterName) { RequestFilterChain requestChain = requestChain(pattern); if (requestChain == null) { return null; } if (requestChain.getFilterNames().contains(filterName)) { //JD: perhaps we should move it return null; } return requestChain; } RequestFilterChain requestChain(String pattern) { for (RequestFilterChain requestChain : requestChains) { if (requestChain.getPatterns().contains(pattern)) { return requestChain; } } return null; } }