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