/**********************************************************************************
*
* $Id: RoleFilter.java 105079 2012-02-24 23:08:11Z ottenhoff@longsight.com $
*
***********************************************************************************
*
* Copyright (c) 2005, 2006, 2007, 2008 The Sakai Foundation, The MIT Corporation
*
* Licensed under the Educational Community License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.opensource.org/licenses/ECL-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
**********************************************************************************/
package org.sakaiproject.tool.gradebook.ui;
import java.io.IOException;
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.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.sakaiproject.tool.gradebook.facades.Authn;
import org.sakaiproject.tool.gradebook.facades.Authz;
import org.sakaiproject.tool.gradebook.facades.ContextManagement;
import org.springframework.context.ApplicationContext;
import org.springframework.web.context.WebApplicationContext;
import org.sakaiproject.component.cover.ServerConfigurationService;
/**
* A role-based authorization filter which takes four parameters:
* <ul>
* <li>authnServiceBean - The Spring-configured authentication service
* <li>authzServiceBean - The Spring-configured authorization service
* <li>role - A string describing which role is required to access this resource
* <li>selectGradebookRedirect - Where to go if a gradebook doesn't seem to have
* been selected yet; this can happen on an application redeploy to Tomcat,
* since JSF beans will be lost but authentication for the session might
* still be active
* </ul>
*
* Because Tomcat 5.* developers decided to take an eccentric interpretation of the
* ambiguous language in the Servlet specification, Tomcat doesn't accept the
* combination of directories and wildcards for the "url-pattern" of the
* filter mapping. As a result, the filter has to do some of that work itself.
* In this case, we guard all pages at the top of the servlet path but let
* other URLs (e.g., "/test/login.jsf") pass through.
*/
public class RoleFilter implements Filter {
private static Log logger = LogFactory.getLog(RoleFilter.class);
private String authnServiceBeanName;
private String authzServiceBeanName;
private String contextManagementServiceBeanName;
private String authorizationFilterConfigurationBeanName;
private String selectGradebookRedirect;
private ApplicationContext ac;
public void init(FilterConfig filterConfig) throws ServletException {
if(logger.isInfoEnabled()) logger.info("Initializing gradebook role filter");
ac = (ApplicationContext)filterConfig.getServletContext().getAttribute(WebApplicationContext.ROOT_WEB_APPLICATION_CONTEXT_ATTRIBUTE);
authnServiceBeanName = filterConfig.getInitParameter("authnServiceBean");
authzServiceBeanName = filterConfig.getInitParameter("authzServiceBean");
contextManagementServiceBeanName = filterConfig.getInitParameter("contextManagementServiceBean");
authorizationFilterConfigurationBeanName = filterConfig.getInitParameter("authorizationFilterConfigurationBean");
selectGradebookRedirect = filterConfig.getInitParameter("selectGradebookRedirect");
}
public void doFilter(ServletRequest servletRequest, ServletResponse response, FilterChain chain)
throws IOException, ServletException {
HttpServletRequest request = (HttpServletRequest)servletRequest;
String servletPath = request.getServletPath();
if (logger.isDebugEnabled()) logger.debug("Filtering request for servletPath=" + servletPath);
servletPath = servletPath.replaceFirst("^/", "");
if (servletPath.indexOf("/") >= 0) {
// Only protect the top-level folder, to allow for login through
// a subdirectory, shared resource files, and so on.
chain.doFilter(request, response);
return;
}
Authn authnService = (Authn)ac.getBean(authnServiceBeanName);
Authz authzService = (Authz)ac.getBean(authzServiceBeanName);
ContextManagement contextManagementService = (ContextManagement)ac.getBean(contextManagementServiceBeanName);
AuthorizationFilterConfigurationBean authorizationFilterConfigurationBean = (AuthorizationFilterConfigurationBean)ac.getBean(authorizationFilterConfigurationBeanName);
authnService.setAuthnContext(request);
String userUid = authnService.getUserUid();
if (logger.isDebugEnabled()) logger.debug("Filtering request for user " + userUid + ", pathInfo=" + request.getPathInfo());
// Try to get the currently selected gradebook UID, if any
// First check the context management service.
// Then check for a locally maintained value.
String gradebookUid = contextManagementService.getGradebookUid(request);
if(logger.isDebugEnabled()) logger.debug("contextManagementService.getGradebookUid=" + gradebookUid);
if (gradebookUid == null) {
gradebookUid = GradebookBean.getGradebookUidFromRequest(request);
if (logger.isDebugEnabled()) logger.debug("GradebookBean.getGradebookUidFromRequest=" + gradebookUid);
}
if (gradebookUid != null) {
if(logger.isDebugEnabled()) logger.debug("gradebookUid=" + gradebookUid + ", userUid=" + userUid);
// Get the name of the page from the servlet path.
String[] splitPath = servletPath.split("[./]");
String pageName = splitPath[0];
boolean isAuthorized;
if (authzService.isUserAbleToGrade(gradebookUid) &&
authorizationFilterConfigurationBean.getUserAbleToGradePages().contains(pageName)) {
isAuthorized = true;
} else if (authzService.isUserAbleToEditAssessments(gradebookUid) && authorizationFilterConfigurationBean.getUserAbleToEditPages().contains(pageName)) {
isAuthorized = true;
} else if (authzService.isUserAbleToViewOwnGrades(gradebookUid) && authorizationFilterConfigurationBean.getUserAbleToViewOwnGradesPages().contains(pageName)) {
isAuthorized = true;
} else {
isAuthorized = false;
}
// SAK-13408 - This fix addresses the problem of the filter receiving a blank field on WebSphere.
// Without this, users would be denied access to the tool.
if("websphere".equals(ServerConfigurationService.getString("servlet.container")) && (isAuthorized || pageName.equals("")) ) {
chain.doFilter(request, response);
} else if ( !"websphere".equals(ServerConfigurationService.getString("servlet.container")) && isAuthorized) {
chain.doFilter(request, response);
} else {
logger.error("AUTHORIZATION FAILURE: User " + userUid + " in gradebook " + gradebookUid + " attempted to reach URL " + request.getRequestURL());
((HttpServletResponse)response).sendError(HttpServletResponse.SC_UNAUTHORIZED);
}
} else {
if (selectGradebookRedirect != null) {
((HttpServletResponse)response).sendRedirect(selectGradebookRedirect);
} else {
// TODO Any better status code for this?
((HttpServletResponse)response).sendError(HttpServletResponse.SC_UNAUTHORIZED);
}
}
}
public void destroy() {
}
}