001 package org.tynamo.security.filter;
002
003 import org.apache.shiro.util.StringUtils;
004 import org.apache.shiro.web.filter.AccessControlFilter;
005 import org.apache.shiro.web.filter.authc.AuthenticationFilter;
006 import org.apache.shiro.web.filter.authz.AuthorizationFilter;
007 import org.apache.shiro.web.filter.mgt.DefaultFilterChainManager;
008 import org.apache.shiro.web.filter.mgt.FilterChainManager;
009 import org.apache.shiro.web.filter.mgt.PathMatchingFilterChainResolver;
010 import org.apache.shiro.web.mgt.WebSecurityManager;
011 import org.apache.shiro.web.servlet.IniShiroFilter;
012 import org.apache.tapestry5.ioc.annotations.Inject;
013 import org.apache.tapestry5.ioc.annotations.ServiceId;
014 import org.apache.tapestry5.ioc.annotations.Symbol;
015 import org.apache.tapestry5.services.ApplicationGlobals;
016 import org.apache.tapestry5.services.HttpServletRequestFilter;
017 import org.apache.tapestry5.services.HttpServletRequestHandler;
018 import org.slf4j.Logger;
019 import org.tynamo.security.FilterChainDefinition;
020 import org.tynamo.security.SecuritySymbols;
021
022 import javax.servlet.*;
023 import javax.servlet.http.HttpServletRequest;
024 import javax.servlet.http.HttpServletResponse;
025 import java.io.IOException;
026 import java.util.Enumeration;
027 import java.util.List;
028 import java.util.Map;
029
030 @ServiceId("SecurityRequestFilter")
031 public class SecurityRequestFilter extends IniShiroFilter implements HttpServletRequestFilter
032 {
033
034 private IniShiroFilter shiroFilter;
035 private Logger logger;
036
037 private String loginUrl;
038 private String unauthorizedUrl;
039 private String successUrl;
040
041 public SecurityRequestFilter(List<FilterChainDefinition> filterChainDefinitions,
042 WebSecurityManager securityManager,
043 Logger logger,
044 @Inject @Symbol(SecuritySymbols.SUCCESS_URL) String successUrl,
045 @Inject @Symbol(SecuritySymbols.LOGIN_URL) String loginUrl,
046 @Inject @Symbol(SecuritySymbols.UNAUTHORIZED_URL) String unauthorizedUrl,
047 @Inject @Symbol(SecuritySymbols.CONFIG_PATH) String configPath,
048 @Inject @Symbol(SecuritySymbols.SHOULD_LOAD_INI_FROM_CONFIG_PATH) boolean shouldLoadIniFromPath,
049 ApplicationGlobals globals) throws Exception
050 {
051 final ServletContext servletContext = globals.getServletContext();
052
053 this.logger = logger;
054 this.loginUrl = loginUrl;
055 this.unauthorizedUrl = unauthorizedUrl;
056 this.successUrl = successUrl;
057
058 shiroFilter = new IniShiroFilter();
059 if (shouldLoadIniFromPath)
060 {
061 shiroFilter.setConfigPath(configPath);
062 shiroFilter.init(new FilterConfig()
063 {
064
065 @Override
066 public String getFilterName()
067 {
068 return "ShiroFilter";
069 }
070
071 @Override
072 public ServletContext getServletContext()
073 {
074 return servletContext;
075 }
076
077 @Override
078 public String getInitParameter(String name)
079 {
080 return null; //To change body of implemented methods use File | Settings | File Templates.
081 }
082
083 @Override
084 public Enumeration getInitParameterNames()
085 {
086 return new Enumeration()
087 {
088
089 @Override
090 public boolean hasMoreElements()
091 {
092 return false;
093 }
094
095 @Override
096 public Object nextElement()
097 {
098 return null; //To change body of implemented methods use File | Settings | File Templates.
099 }
100 };
101 }
102 }
103 );
104 }
105
106 shiroFilter.setSecurityManager(securityManager);
107
108 PathMatchingFilterChainResolver chainResolver = (PathMatchingFilterChainResolver) shiroFilter.getFilterChainResolver();
109 if (chainResolver == null)
110 {
111 FilterChainManager manager = new DefaultFilterChainManager();
112 //Expose the constructed FilterChainManager by first wrapping it in a
113 // FilterChainResolver implementation. The ShiroFilter implementations
114 // do not know about FilterChainManagers - only resolvers:
115 chainResolver = new PathMatchingFilterChainResolver();
116 chainResolver.setFilterChainManager(manager);
117 shiroFilter.setFilterChainResolver(chainResolver);
118 }
119
120 Map<String, Filter> defaultFilters = chainResolver.getFilterChainManager().getFilters();
121 //apply global settings if necessary:
122 for (Filter filter : defaultFilters.values())
123 {
124 applyGlobalPropertiesIfNecessary(filter);
125 }
126
127 /*
128 //Apply the acquired and/or configured filters:
129 Map<String, Filter> filters = getFilters();
130 if (!CollectionUtils.isEmpty(filters)) {
131 for (Map.Entry<String, Filter> entry : filters.entrySet()) {
132 String name = entry.getKey();
133 Filter filter = entry.getValue();
134 applyGlobalPropertiesIfNecessary(filter);
135 if (filter instanceof Nameable) {
136 ((Nameable) filter).setName(name);
137 }
138 //'init' argument is false, since Spring-configured filters should be initialized
139 //in Spring (i.e. 'init-method=blah') or implement InitializingBean:
140 manager.addFilter(name, filter, false);
141 }
142 }
143 */
144
145 //build up the chains:
146 for (FilterChainDefinition filterChainDefinition : filterChainDefinitions)
147 {
148 logger.debug("adding filterChainDefinition: " + filterChainDefinition);
149 chainResolver.getFilterChainManager().createChain(filterChainDefinition.getAntUrlPathExpression(), filterChainDefinition.getChainDefinition());
150 }
151
152 }
153
154 @Override
155 public boolean service(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse,
156 final HttpServletRequestHandler handler) throws IOException
157 {
158 // Assume request handled if filter chain is NOT executed
159 final boolean[] res = new boolean[]{true};
160 try
161 {
162 shiroFilter.doFilter(httpServletRequest, httpServletResponse, new FilterChain()
163 {
164 public void doFilter(final ServletRequest request,
165 final ServletResponse response) throws IOException, ServletException
166 {
167 res[0] = handler.service((HttpServletRequest) request, (HttpServletResponse) response);
168 }
169 });
170 } catch (ServletException e)
171 {
172 IOException ex = new IOException(e.getMessage());
173 ex.initCause(e);
174 throw ex;
175 }
176 return res[0];
177 }
178
179 private void applyLoginUrlIfNecessary(Filter filter)
180 {
181 if (StringUtils.hasText(loginUrl) && (filter instanceof AccessControlFilter))
182 {
183 AccessControlFilter acFilter = (AccessControlFilter) filter;
184 //only apply the login url if they haven't explicitly configured one already:
185 String existingLoginUrl = acFilter.getLoginUrl();
186 if (AccessControlFilter.DEFAULT_LOGIN_URL.equals(existingLoginUrl))
187 {
188 acFilter.setLoginUrl(loginUrl);
189 }
190 }
191 }
192
193 private void applySuccessUrlIfNecessary(Filter filter)
194 {
195 if (StringUtils.hasText(successUrl) && (filter instanceof AuthenticationFilter))
196 {
197 AuthenticationFilter authcFilter = (AuthenticationFilter) filter;
198 //only apply the successUrl if they haven't explicitly configured one already:
199 String existingSuccessUrl = authcFilter.getSuccessUrl();
200 if (AuthenticationFilter.DEFAULT_SUCCESS_URL.equals(existingSuccessUrl))
201 {
202 authcFilter.setSuccessUrl(successUrl);
203 }
204 }
205 }
206
207 private void applyUnauthorizedUrlIfNecessary(Filter filter)
208 {
209 if (StringUtils.hasText(unauthorizedUrl) && (filter instanceof AuthorizationFilter))
210 {
211 AuthorizationFilter authzFilter = (AuthorizationFilter) filter;
212 //only apply the unauthorizedUrl if they haven't explicitly configured one already:
213 String existingUnauthorizedUrl = authzFilter.getUnauthorizedUrl();
214 if (existingUnauthorizedUrl == null)
215 {
216 authzFilter.setUnauthorizedUrl(unauthorizedUrl);
217 }
218 }
219 }
220
221 private void applyGlobalPropertiesIfNecessary(Filter filter)
222 {
223 applyLoginUrlIfNecessary(filter);
224 applySuccessUrlIfNecessary(filter);
225 applyUnauthorizedUrlIfNecessary(filter);
226 }
227 }