001: /**********************************************************************************
002: *
003: * $Id: RoleFilter.java 19997 2006-12-22 19:37:19Z ray@media.berkeley.edu $
004: *
005: ***********************************************************************************
006: *
007: * Copyright (c) 2005 The Regents of the University of California, The MIT Corporation
008: *
009: * Licensed under the Educational Community License, Version 1.0 (the "License");
010: * you may not use this file except in compliance with the License.
011: * You may obtain a copy of the License at
012: *
013: * http://www.opensource.org/licenses/ecl1.php
014: *
015: * Unless required by applicable law or agreed to in writing, software
016: * distributed under the License is distributed on an "AS IS" BASIS,
017: * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
018: * See the License for the specific language governing permissions and
019: * limitations under the License.
020: *
021: **********************************************************************************/package org.sakaiproject.tool.gradebook.ui;
022:
023: import java.io.IOException;
024:
025: import javax.servlet.Filter;
026: import javax.servlet.FilterChain;
027: import javax.servlet.FilterConfig;
028: import javax.servlet.ServletException;
029: import javax.servlet.ServletRequest;
030: import javax.servlet.ServletResponse;
031: import javax.servlet.http.HttpServletRequest;
032: import javax.servlet.http.HttpServletResponse;
033:
034: import org.apache.commons.logging.Log;
035: import org.apache.commons.logging.LogFactory;
036: import org.sakaiproject.tool.gradebook.facades.Authn;
037: import org.sakaiproject.tool.gradebook.facades.Authz;
038: import org.sakaiproject.tool.gradebook.facades.ContextManagement;
039: import org.springframework.context.ApplicationContext;
040: import org.springframework.web.context.WebApplicationContext;
041:
042: /**
043: * A role-based authorization filter which takes four parameters:
044: * <ul>
045: * <li>authnServiceBean - The Spring-configured authentication service
046: * <li>authzServiceBean - The Spring-configured authorization service
047: * <li>role - A string describing which role is required to access this resource
048: * <li>selectGradebookRedirect - Where to go if a gradebook doesn't seem to have
049: * been selected yet; this can happen on an application redeploy to Tomcat,
050: * since JSF beans will be lost but authentication for the session might
051: * still be active
052: * </ul>
053: *
054: * Because Tomcat 5.* developers decided to take an eccentric interpretation of the
055: * ambiguous language in the Servlet specification, Tomcat doesn't accept the
056: * combination of directories and wildcards for the "url-pattern" of the
057: * filter mapping. As a result, the filter has to do some of that work itself.
058: * In this case, we guard all pages at the top of the servlet path but let
059: * other URLs (e.g., "/test/login.jsf") pass through.
060: */
061: public class RoleFilter implements Filter {
062: private static Log logger = LogFactory.getLog(RoleFilter.class);
063:
064: private String authnServiceBeanName;
065: private String authzServiceBeanName;
066: private String contextManagementServiceBeanName;
067: private String authorizationFilterConfigurationBeanName;
068: private String selectGradebookRedirect;
069:
070: private ApplicationContext ac;
071:
072: public void init(FilterConfig filterConfig) throws ServletException {
073: if (logger.isInfoEnabled())
074: logger.info("Initializing gradebook role filter");
075:
076: ac = (ApplicationContext) filterConfig
077: .getServletContext()
078: .getAttribute(
079: WebApplicationContext.ROOT_WEB_APPLICATION_CONTEXT_ATTRIBUTE);
080:
081: authnServiceBeanName = filterConfig
082: .getInitParameter("authnServiceBean");
083: authzServiceBeanName = filterConfig
084: .getInitParameter("authzServiceBean");
085: contextManagementServiceBeanName = filterConfig
086: .getInitParameter("contextManagementServiceBean");
087: authorizationFilterConfigurationBeanName = filterConfig
088: .getInitParameter("authorizationFilterConfigurationBean");
089: selectGradebookRedirect = filterConfig
090: .getInitParameter("selectGradebookRedirect");
091: }
092:
093: public void doFilter(ServletRequest servletRequest,
094: ServletResponse response, FilterChain chain)
095: throws IOException, ServletException {
096:
097: HttpServletRequest request = (HttpServletRequest) servletRequest;
098: String servletPath = request.getServletPath();
099: if (logger.isDebugEnabled())
100: logger.debug("Filtering request for servletPath="
101: + servletPath);
102: servletPath = servletPath.replaceFirst("^/", "");
103: if (servletPath.indexOf("/") >= 0) {
104: // Only protect the top-level folder, to allow for login through
105: // a subdirectory, shared resource files, and so on.
106: chain.doFilter(request, response);
107: return;
108: }
109:
110: Authn authnService = (Authn) ac.getBean(authnServiceBeanName);
111: Authz authzService = (Authz) ac.getBean(authzServiceBeanName);
112: ContextManagement contextManagementService = (ContextManagement) ac
113: .getBean(contextManagementServiceBeanName);
114: AuthorizationFilterConfigurationBean authorizationFilterConfigurationBean = (AuthorizationFilterConfigurationBean) ac
115: .getBean(authorizationFilterConfigurationBeanName);
116: authnService.setAuthnContext(request);
117: String userUid = authnService.getUserUid();
118:
119: if (logger.isDebugEnabled())
120: logger.debug("Filtering request for user " + userUid
121: + ", pathInfo=" + request.getPathInfo());
122:
123: // Try to get the currently selected gradebook UID, if any
124: // First check the context management service.
125: // Then check for a locally maintained value.
126: String gradebookUid = contextManagementService
127: .getGradebookUid(request);
128: if (logger.isDebugEnabled())
129: logger.debug("contextManagementService.getGradebookUid="
130: + gradebookUid);
131: if (gradebookUid == null) {
132: gradebookUid = GradebookBean
133: .getGradebookUidFromRequest(request);
134: if (logger.isDebugEnabled())
135: logger
136: .debug("GradebookBean.getGradebookUidFromRequest="
137: + gradebookUid);
138: }
139:
140: if (gradebookUid != null) {
141: if (logger.isDebugEnabled())
142: logger.debug("gradebookUid=" + gradebookUid
143: + ", userUid=" + userUid);
144:
145: // Get the name of the page from the servlet path.
146: String[] splitPath = servletPath.split("[./]");
147: String pageName = splitPath[0];
148:
149: boolean isAuthorized;
150: if (authzService.isUserAbleToGrade(gradebookUid)
151: && authorizationFilterConfigurationBean
152: .getUserAbleToGradePages().contains(
153: pageName)) {
154: isAuthorized = true;
155: } else if (authzService
156: .isUserAbleToEditAssessments(gradebookUid)
157: && authorizationFilterConfigurationBean
158: .getUserAbleToEditPages()
159: .contains(pageName)) {
160: isAuthorized = true;
161: } else if (authzService
162: .isUserAbleToViewOwnGrades(gradebookUid)
163: && authorizationFilterConfigurationBean
164: .getUserAbleToViewOwnGradesPages()
165: .contains(pageName)) {
166: isAuthorized = true;
167: } else {
168: isAuthorized = false;
169: }
170:
171: if (isAuthorized) {
172: chain.doFilter(request, response);
173: } else {
174: logger.error("AUTHORIZATION FAILURE: User " + userUid
175: + " in gradebook " + gradebookUid
176: + " attempted to reach URL "
177: + request.getRequestURL());
178: ((HttpServletResponse) response)
179: .sendError(HttpServletResponse.SC_UNAUTHORIZED);
180: }
181: } else {
182: if (selectGradebookRedirect != null) {
183: ((HttpServletResponse) response)
184: .sendRedirect(selectGradebookRedirect);
185: } else {
186: // TODO Any better status code for this?
187: ((HttpServletResponse) response)
188: .sendError(HttpServletResponse.SC_UNAUTHORIZED);
189: }
190: }
191: }
192:
193: public void destroy() {
194: }
195: }
|