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