package edu.harvard.med.screensaver.ui.arch.auth.servlet;
import java.io.IOException;
import java.util.Set;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import javax.servlet.Filter;
import javax.servlet.FilterChain;
import javax.servlet.FilterConfig;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.apache.log4j.Logger;
import com.google.common.collect.Sets;
import edu.harvard.med.screensaver.util.StringUtils;
/**
* This filter will perform Authentication for selected URL-patterns.
* <p/>
* Restrict access for a set of servlet paths to a role.<br/>
* Params:<br/>
* <br/>
* - roles: comma separated list of roles<br/>
* <br/>
* - preRegexString: a regex pattern that is used to pre-filter;<br/>
* group(1) for this pattern (the "subDir") is used in a second-level match<br/>
* against each of the "regexes". Should have the form regex_pattern(subDir pattern)<br/>
* <br/>
* - regexes: comma separated list of regex patterns<br/>
* to match against the group(1) match (the "subDir") from the preRegexString<br/>
* <br/>
* Operation: if one of the regexes matches a subDir, then see if the current user is in<br/>
* one of the roles (using HttpServletRequest.isUserInRole )<br/>
* <br/>
* <br/>
* references: <br/>
* http://publib.boulder.ibm.com/infocenter/wasinfo/v6r1/index.jsp?topic=/com.ibm.websphere.express.doc/info/exp/ae/tsec_servlet.html<br/>
* http://java.sun.com/javaee/5/docs/tutorial/doc/bncav.html
*
*/
public class AuthenticationFilter implements Filter
{
private static Logger log = Logger.getLogger(AuthenticationFilter.class);
private FilterConfig config = null;
private Pattern _preRegex;
private Set<Pattern> _regexs = Sets.newHashSet();
private Set<String> _roles = Sets.newHashSet();
public void init(FilterConfig config) throws ServletException
{
this.config = config;
String preRegexString = this.config.getInitParameter("preRegexString");
String regexesString = this.config.getInitParameter("regexs");
String roles = this.config.getInitParameter("roles");
String errMsg = "";
if (StringUtils.isEmpty(preRegexString))
{
errMsg += "Param \"preRegexString\" must not be empty";
}
if (StringUtils.isEmpty(regexesString))
{
errMsg += (errMsg.length()==0?"":", ") + "Param \"regexs\" must not be empty";
}
if (StringUtils.isEmpty(roles))
{
errMsg += (errMsg.length()==0?"":", ") + "Param \"roles\" must not be empty";
}
if(errMsg.length() > 0 )
{
throw new ServletException("Authentication Servlet Usage: " + errMsg );
}
if (log.isDebugEnabled()) {
log.debug("regexesString:" + regexesString);
}
_preRegex = Pattern.compile(preRegexString);
for (String regex:regexesString.split(","))
{
if (log.isDebugEnabled()) {
log.debug("compile: " + regex);
}
_regexs.add(Pattern.compile(regex));
}
for (String role:roles.split(","))
{
_roles.add(role);
}
}
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain)
throws IOException, ServletException
{
if (!(request instanceof HttpServletRequest) || !(response instanceof HttpServletResponse)) {
throw new ServletException("SecurityFilter only accepts HTTP requests");
}
if (request instanceof HttpServletRequest) {
HttpServletRequest req = (HttpServletRequest) request;
HttpServletResponse res = (HttpServletResponse) response;
String pathInfo = req.getServletPath();
if (pathInfo != null) {
Matcher match = _preRegex.matcher(pathInfo);
if (match.matches()) {
String subdir = match.group(1);
for (Pattern p : _regexs) {
if (p.matcher(subdir).matches()) {
boolean roleFound = false;
if (req.getUserPrincipal() != null) {
for (String role : _roles) {
if (req.isUserInRole(role)) {
roleFound = true;
break;
}
}
}
if (!roleFound) {
if (req.getUserPrincipal() != null) {
log.info("access for the user \"" + req.getUserPrincipal().getName() + "\" to: " + pathInfo
+ ", subdir: " + subdir
+ " has been denied!");
}
else {
log.info("access for unauthenticated user at: " + req.getRemoteAddr() + " to: " + pathInfo + ", subdir: " +
subdir + " has been denied!");
}
res.sendError(javax.servlet.http.HttpServletResponse.SC_FORBIDDEN);
return;
}
}// match subdir
}
}// match preRegex
}
// post login action
chain.doFilter(request, response);
}
else {
// only allow http servlet requests
throw new ServletException("Invalid request type (must be http servlet request): "
+ request.getClass().getName());
}
}
public void destroy()
{
// TODO Auto-generated method stub
}
}