Index: lams_build/lib/lams/lams.jar =================================================================== diff -u -r5e39743e8bd500d0e121cf4c95b9c9fc77eb80fc -r38b5da8f9b986f835a4dde123bd09954a4b6e171 Binary files differ Index: lams_central/src/java/org/lamsfoundation/lams/web/DisplayGroupAction.java =================================================================== diff -u -r9fb16007bc803d29180994effaed30ebb0a2e561 -r38b5da8f9b986f835a4dde123bd09954a4b6e171 --- lams_central/src/java/org/lamsfoundation/lams/web/DisplayGroupAction.java (.../DisplayGroupAction.java) (revision 9fb16007bc803d29180994effaed30ebb0a2e561) +++ lams_central/src/java/org/lamsfoundation/lams/web/DisplayGroupAction.java (.../DisplayGroupAction.java) (revision 38b5da8f9b986f835a4dde123bd09954a4b6e171) @@ -23,11 +23,9 @@ /* $Id$ */ package org.lamsfoundation.lams.web; -import java.io.IOException; import java.sql.SQLException; import java.util.ArrayList; import java.util.Collections; -import java.util.Comparator; import java.util.Iterator; import java.util.LinkedList; import java.util.List; @@ -47,11 +45,11 @@ import org.lamsfoundation.lams.index.IndexLessonBean; import org.lamsfoundation.lams.index.IndexLinkBean; import org.lamsfoundation.lams.index.IndexOrgBean; -import org.lamsfoundation.lams.learningdesign.dto.LearningLibraryDTO; -import org.lamsfoundation.lams.learningdesign.dto.LibraryActivityDTO; import org.lamsfoundation.lams.learningdesign.service.ILearningDesignService; import org.lamsfoundation.lams.lesson.Lesson; import org.lamsfoundation.lams.lesson.service.LessonService; +import org.lamsfoundation.lams.security.ISecurityService; +import org.lamsfoundation.lams.security.SecurityException; import org.lamsfoundation.lams.usermanagement.Organisation; import org.lamsfoundation.lams.usermanagement.OrganisationState; import org.lamsfoundation.lams.usermanagement.OrganisationType; @@ -75,6 +73,8 @@ private static IUserManagementService service; private static LessonService lessonService; private static ILearningDesignService learningDesignService; + private static ISecurityService securityService; + private Integer stateId = OrganisationState.ACTIVE; @Override @@ -91,6 +91,16 @@ } if (org != null) { + User user = getUser(request.getRemoteUser()); + try { + getSecurityService().hasOrgRole(orgId, user.getUserId(), Role.LEARNER, Role.MONITOR, Role.AUTHOR, + Role.GROUP_MANAGER); + } catch (SecurityException e) { + log.error("Cannot display group", e); + response.sendError(HttpServletResponse.SC_FORBIDDEN, "The user is not a part of the organisation"); + return null; + } + boolean allowSorting = false; List roles = new ArrayList(); List userOrganisationRoles = getService().getUserOrganisationRoles(orgId, @@ -211,10 +221,9 @@ @SuppressWarnings("unchecked") private IndexOrgBean populateContentsOrgBean(IndexOrgBean orgBean, Organisation org, List roles, String username, boolean isSysAdmin) throws SQLException, NamingException { - User user = (User) getService().findByProperty(User.class, "login", username).get(0); - // set lesson beans - Map map = populateLessonBeans(user.getUserId(), org.getOrganisationId(), roles); + Map map = populateLessonBeans(getUser(username).getUserId(), org.getOrganisationId(), + roles); List lessonBeans = IndexUtils.sortLessonBeans(org.getOrderedLessonIds(), map); orgBean.setLessons(lessonBeans); @@ -364,6 +373,10 @@ return map; } + private User getUser(String login) { + return (User) getService().findByProperty(User.class, "login", login).get(0); + } + private IUserManagementService getService() { if (DisplayGroupAction.service == null) { WebApplicationContext ctx = WebApplicationContextUtils.getRequiredWebApplicationContext(getServlet() @@ -390,4 +403,13 @@ } return DisplayGroupAction.learningDesignService; } + + private ISecurityService getSecurityService() { + if (securityService == null) { + WebApplicationContext ctx = WebApplicationContextUtils.getRequiredWebApplicationContext(getServlet() + .getServletContext()); + securityService = (ISecurityService) ctx.getBean("securityService"); + } + return securityService; + } } \ No newline at end of file Index: lams_central/src/java/org/lamsfoundation/lams/web/HomeAction.java =================================================================== diff -u -r252b0d692d18823c182862060f13f93ee517b868 -r38b5da8f9b986f835a4dde123bd09954a4b6e171 --- lams_central/src/java/org/lamsfoundation/lams/web/HomeAction.java (.../HomeAction.java) (revision 252b0d692d18823c182862060f13f93ee517b868) +++ lams_central/src/java/org/lamsfoundation/lams/web/HomeAction.java (.../HomeAction.java) (revision 38b5da8f9b986f835a4dde123bd09954a4b6e171) @@ -34,7 +34,6 @@ import java.util.TreeSet; import java.util.Vector; -import javax.servlet.RequestDispatcher; import javax.servlet.ServletException; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; @@ -58,6 +57,8 @@ import org.lamsfoundation.lams.lesson.dto.LessonDTO; import org.lamsfoundation.lams.lesson.service.ILessonService; import org.lamsfoundation.lams.lesson.util.LessonDTOComparator; +import org.lamsfoundation.lams.security.ISecurityService; +import org.lamsfoundation.lams.security.SecurityException; import org.lamsfoundation.lams.usermanagement.Organisation; import org.lamsfoundation.lams.usermanagement.Role; import org.lamsfoundation.lams.usermanagement.User; @@ -101,6 +102,7 @@ private static ILearningDesignService learningDesignService; private static IGroupUserDAO groupUserDAO; private static IWorkspaceManagementService workspaceManagementService; + private static ISecurityService securityService; /** * request for sysadmin environment @@ -178,7 +180,7 @@ if (!lesson.isLessonAccessibleForLearner()) { return displayMessage(mapping, req, "error.lesson.not.accessible.for.learners"); } - + // show lesson intro page if required and it's not been shown already boolean isLessonIntroWatched = WebUtil.readBooleanParam(req, "isLessonIntroWatched", false); if (lesson.isEnableLessonIntro() && !isLessonIntroWatched) { @@ -202,12 +204,12 @@ } return mapping.findForward("lessonIntro"); } - + if (lesson.getLearnerRestart()) { // start the lesson from the beginning each time getLessonService().removeLearnerProgress(lessonId, user.getUserID()); } - + if (mode != null) { req.setAttribute(AttributeNames.PARAM_MODE, mode); } @@ -224,10 +226,11 @@ /* Date Format for Chat room append */ DateFormat sfm = new SimpleDateFormat("yyyyMMdd_HHmmss"); req.setAttribute(AttributeNames.PARAM_CREATE_DATE_TIME, sfm.format(lesson.getCreateDateTime())); - - //forward to /lams/learning/main.jsp + + // forward to /lams/learning/main.jsp String serverURLContextPath = Configuration.get(ConfigurationKeys.SERVER_URL_CONTEXT_PATH); - serverURLContextPath = serverURLContextPath.startsWith("/") ? serverURLContextPath : "/" + serverURLContextPath; + serverURLContextPath = serverURLContextPath.startsWith("/") ? serverURLContextPath : "/" + + serverURLContextPath; serverURLContextPath += serverURLContextPath.endsWith("/") ? "" : "/"; getServlet().getServletContext().getContext(serverURLContextPath + "learning") .getRequestDispatcher("/main.jsp").forward(req, res); @@ -307,6 +310,7 @@ if (HomeAction.log.isDebugEnabled()) { HomeAction.log.debug("Requested Lesson Monitor"); } + Long lessonId = WebUtil.readLongParam(req, AttributeNames.PARAM_LESSON_ID); UserDTO user = getUser(); if (user == null) { @@ -331,13 +335,20 @@ HttpServletResponse res) throws IOException, UserAccessDeniedException, JSONException, RepositoryCheckedException { UserDTO userDTO = getUser(); + Integer organisationID = new Integer(WebUtil.readIntParam(req, "organisationID")); + try { + getSecurityService().hasOrgRole(organisationID, userDTO.getUserID(), Role.MONITOR, Role.GROUP_MANAGER); + } catch (SecurityException e) { + HomeAction.log.error("Cannot add lesson", e); + res.sendError(HttpServletResponse.SC_FORBIDDEN, "User is not a monitor in the given lesson"); + return null; + } + // get all user accessible folders and LD descriptions as JSON String folderContentsJSON = getWorkspaceManagementService().getFolderContentsJSON(null, userDTO.getUserID(), false); req.setAttribute("folderContents", folderContentsJSON); - - Integer organisationID = new Integer(WebUtil.readIntParam(req, "organisationID")); JSONObject users = new JSONObject(); // get learners available for newly created lesson @@ -395,8 +406,8 @@ RepositoryCheckedException { Integer folderID = WebUtil.readIntParam(req, "folderID", true); boolean allowInvalidDesigns = WebUtil.readBooleanParam(req, "allowInvalidDesigns", false); - String folderContentsJSON = getWorkspaceManagementService().getFolderContentsJSON(folderID, getUser().getUserID(), - allowInvalidDesigns); + String folderContentsJSON = getWorkspaceManagementService().getFolderContentsJSON(folderID, + getUser().getUserID(), allowInvalidDesigns); res.setContentType("application/json;charset=UTF-8"); res.getWriter().print(folderContentsJSON); @@ -516,6 +527,16 @@ return HomeAction.workspaceManagementService; } + private ISecurityService getSecurityService() { + if (HomeAction.securityService == null) { + WebApplicationContext webContext = WebApplicationContextUtils.getRequiredWebApplicationContext(getServlet() + .getServletContext()); + HomeAction.securityService = (ISecurityService) webContext.getBean("securityService"); + } + + return HomeAction.securityService; + } + private UserDTO getUser() { HttpSession ss = SessionManager.getSession(); return (UserDTO) ss.getAttribute(AttributeNames.USER); Index: lams_common/src/java/org/lamsfoundation/lams/commonContext.xml =================================================================== diff -u -rdb8cd59179f23576cd809e7657885236cfafa60b -r38b5da8f9b986f835a4dde123bd09954a4b6e171 --- lams_common/src/java/org/lamsfoundation/lams/commonContext.xml (.../commonContext.xml) (revision db8cd59179f23576cd809e7657885236cfafa60b) +++ lams_common/src/java/org/lamsfoundation/lams/commonContext.xml (.../commonContext.xml) (revision 38b5da8f9b986f835a4dde123bd09954a4b6e171) @@ -298,8 +298,23 @@ - + + + + + + + + true + + + PROPAGATION_REQUIRED,readOnly + + + + + @@ -411,6 +426,11 @@ + + + + + - + \ No newline at end of file Index: lams_common/src/java/org/lamsfoundation/lams/security/ISecurityDAO.java =================================================================== diff -u --- lams_common/src/java/org/lamsfoundation/lams/security/ISecurityDAO.java (revision 0) +++ lams_common/src/java/org/lamsfoundation/lams/security/ISecurityDAO.java (revision 38b5da8f9b986f835a4dde123bd09954a4b6e171) @@ -0,0 +1,39 @@ +/**************************************************************** + * Copyright (C) 2005 LAMS Foundation (http://lamsfoundation.org) + * ============================================================= + * License Information: http://lamsfoundation.org/licensing/lams/2.0/ + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2.0 + * as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 * USA + * + * http://www.gnu.org/licenses/gpl.txt + * **************************************************************** + */ + +/* $Id$ */ +package org.lamsfoundation.lams.security; + +import java.io.Serializable; + +public interface ISecurityDAO { + @SuppressWarnings("rawtypes") + Object find(Class clazz, Serializable id); + + boolean hasOrgRole(Integer orgId, Integer userId, String... roles); + + boolean isLessonLearner(Long lessonId, Integer userId); + + boolean isLessonMonitor(Long lessonId, Integer userId); + + boolean isSysadmin(Integer userId); +} \ No newline at end of file Index: lams_common/src/java/org/lamsfoundation/lams/security/ISecurityService.java =================================================================== diff -u --- lams_common/src/java/org/lamsfoundation/lams/security/ISecurityService.java (revision 0) +++ lams_common/src/java/org/lamsfoundation/lams/security/ISecurityService.java (revision 38b5da8f9b986f835a4dde123bd09954a4b6e171) @@ -0,0 +1,53 @@ +/**************************************************************** + * Copyright (C) 2006 LAMS Foundation (http://lamsfoundation.org) + * ============================================================= + * License Information: http://lamsfoundation.org/licensing/lams/2.0/ + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2.0 + * as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 + * USA + * + * http://www.gnu.org/licenses/gpl.txt + * **************************************************************** + */ + +package org.lamsfoundation.lams.security; + + +public interface ISecurityService { + + /** + * Checks if the user is a learner in the given lesson. + */ + void checkIsLessonLearner(Long lessonId, Integer userId) throws SecurityException; + + /** + * Checks if the user is a staff member in the given lesson. + */ + void checkIsLessonMonitor(Long lessonId, Integer userId) throws SecurityException; + + /** + * Checks if the user is either a learner or a staff member in the given lesson. + */ + void checkIsLessonParticipant(Long lessonId, Integer userId) throws SecurityException; + + /** + * Checks if the user has a global role of SYSADMIN. + */ + void checkIsSysadmin(Integer userId); + + /** + * Checks if the user has any of the given roles in the given organisation. + */ + void hasOrgRole(Integer orgId, Integer userId, String... roles) throws SecurityException; +} \ No newline at end of file Index: lams_common/src/java/org/lamsfoundation/lams/security/SecurityDAO.java =================================================================== diff -u --- lams_common/src/java/org/lamsfoundation/lams/security/SecurityDAO.java (revision 0) +++ lams_common/src/java/org/lamsfoundation/lams/security/SecurityDAO.java (revision 38b5da8f9b986f835a4dde123bd09954a4b6e171) @@ -0,0 +1,103 @@ +/**************************************************************** + * Copyright (C) 2005 LAMS Foundation (http://lamsfoundation.org) + * ============================================================= + * License Information: http://lamsfoundation.org/licensing/lams/2.0/ + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2.0 + * as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 * USA + * + * http://www.gnu.org/licenses/gpl.txt + * **************************************************************** + */ + +/* $Id$ */ +package org.lamsfoundation.lams.security; + +import java.io.Serializable; + +import org.hibernate.Query; +import org.hibernate.SQLQuery; +import org.lamsfoundation.lams.lesson.Lesson; +import org.lamsfoundation.lams.usermanagement.Role; +import org.lamsfoundation.lams.usermanagement.UserOrganisation; +import org.springframework.orm.hibernate3.support.HibernateDaoSupport; + +public class SecurityDAO extends HibernateDaoSupport implements ISecurityDAO { + + /** + * Checks if the user is a staff member in the given lesson. + */ + private static final String CHECK_LESSON_MONITOR = "FROM " + Lesson.class.getName() + + " AS lesson INNER JOIN lesson.lessonClass.staffGroup.users AS monitor " + + "WHERE lesson.lessonId = ? AND monitor.userId = ?"; + + /** + * Checks if the user is a learner in the given lesson. + */ + private static final String CHECK_LESSON_LEARNER = "SELECT 1 FROM lams_lesson AS l JOIN lams_grouping AS ging " + + "ON l.lesson_id = ? AND l.class_grouping_id = ging.grouping_id JOIN lams_group AS g USING (grouping_id) " + + "JOIN lams_user_group AS ug USING (group_id) WHERE ug.user_id = ?"; + + /** + * Checks if the user has any of the given roles in the given organisation. + */ + private static final String CHECK_ORG_ROLE = "FROM " + UserOrganisation.class.getName() + + " AS userOrganisation INNER JOIN userOrganisation.userOrganisationRoles AS userOrganisationRole " + + "WHERE userOrganisation.organisation.organisationId = :orgId AND userOrganisation.user.userId = :userId " + + "AND userOrganisationRole.role.name IN (:roles)"; + + /** + * Checks if user has a global role of SYSADMIN. + */ + private static final String CHECK_SYSADMIN = "FROM " + + UserOrganisation.class.getName() + + " AS userOrganisation INNER JOIN userOrganisation.userOrganisationRoles AS userOrganisationRole " + + "WHERE userOrganisation.organisation.organisationType.organisationTypeId = 1 AND userOrganisation.user.userId = ? " + + "AND userOrganisationRole.role.name = '" + Role.SYSADMIN + "'"; + + @Override + @SuppressWarnings("rawtypes") + public Object find(Class clazz, Serializable id) { + return getHibernateTemplate().get(clazz, id); + } + + @Override + public boolean hasOrgRole(Integer orgId, Integer userId, String... roles) { + Query query = getHibernateTemplate().getSessionFactory().getCurrentSession() + .createQuery(SecurityDAO.CHECK_ORG_ROLE); + query.setParameter("orgId", orgId); + query.setParameter("userId", userId); + query.setParameterList("roles", roles); + return !query.list().isEmpty(); + } + + @Override + public boolean isLessonLearner(Long lessonId, Integer userId) { + SQLQuery query = getHibernateTemplate().getSessionFactory().getCurrentSession() + .createSQLQuery(SecurityDAO.CHECK_LESSON_LEARNER); + query.setLong(0, lessonId); + query.setInteger(1, userId); + return !query.list().isEmpty(); + } + + @Override + public boolean isLessonMonitor(Long lessonId, Integer userId) { + return !getHibernateTemplate().find(SecurityDAO.CHECK_LESSON_MONITOR, new Object[] { lessonId, userId }) + .isEmpty(); + } + + @Override + public boolean isSysadmin(Integer userId) { + return !getHibernateTemplate().find(SecurityDAO.CHECK_SYSADMIN, new Object[] { userId }).isEmpty(); + } +} \ No newline at end of file Index: lams_common/src/java/org/lamsfoundation/lams/security/SecurityException.java =================================================================== diff -u --- lams_common/src/java/org/lamsfoundation/lams/security/SecurityException.java (revision 0) +++ lams_common/src/java/org/lamsfoundation/lams/security/SecurityException.java (revision 38b5da8f9b986f835a4dde123bd09954a4b6e171) @@ -0,0 +1,37 @@ +/**************************************************************** + * Copyright (C) 2005 LAMS Foundation (http://lamsfoundation.org) + * ============================================================= + * License Information: http://lamsfoundation.org/licensing/lams/2.0/ + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2.0 + * as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 * USA + * + * http://www.gnu.org/licenses/gpl.txt + * **************************************************************** + */ + +/* $Id$ */ +package org.lamsfoundation.lams.security; + +public class SecurityException extends RuntimeException { + public SecurityException() { + } + + public SecurityException(String msg) { + super(msg); + } + + public SecurityException(String message, Throwable cause) { + super(message, cause); + } +} \ No newline at end of file Index: lams_common/src/java/org/lamsfoundation/lams/security/SecurityService.java =================================================================== diff -u --- lams_common/src/java/org/lamsfoundation/lams/security/SecurityService.java (revision 0) +++ lams_common/src/java/org/lamsfoundation/lams/security/SecurityService.java (revision 38b5da8f9b986f835a4dde123bd09954a4b6e171) @@ -0,0 +1,131 @@ +/**************************************************************** + * Copyright (C) 2006 LAMS Foundation (http://lamsfoundation.org) + * ============================================================= + * License Information: http://lamsfoundation.org/licensing/lams/2.0/ + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2.0 + * as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 + * USA + * + * http://www.gnu.org/licenses/gpl.txt + * **************************************************************** + */ + +package org.lamsfoundation.lams.security; + +import java.util.Arrays; + +import org.apache.log4j.Logger; +import org.lamsfoundation.lams.lesson.Lesson; +import org.lamsfoundation.lams.usermanagement.Role; + +public class SecurityService implements ISecurityService { + + private ISecurityDAO securityDAO; + + private static Logger log = Logger.getLogger(SecurityService.class); + + @Override + public void checkIsLessonLearner(Long lessonId, Integer userId) throws SecurityException { + if (lessonId == null) { + throw new SecurityException("Lesson ID is NULL"); + } + if (userId == null) { + throw new SecurityException("User ID is NULL"); + } + + Lesson lesson = (Lesson) securityDAO.find(Lesson.class, lessonId); + if (lesson == null) { + throw new SecurityException("Could not find lesson with ID: " + lessonId); + } + + hasOrgRole(lesson.getOrganisation().getOrganisationId(), userId, Role.LEARNER, Role.MONITOR); + + if (!securityDAO.isSysadmin(userId) && !securityDAO.isLessonLearner(lessonId, userId)) { + throw new SecurityException("User with ID: " + userId + " is not a learner in lesson with ID: " + lessonId); + } + } + + @Override + public void checkIsLessonMonitor(Long lessonId, Integer userId) throws SecurityException { + if (lessonId == null) { + throw new SecurityException("Lesson ID is NULL"); + } + if (userId == null) { + throw new SecurityException("User ID is NULL"); + } + + Lesson lesson = (Lesson) securityDAO.find(Lesson.class, lessonId); + if (lesson == null) { + throw new SecurityException("Could not find lesson with ID: " + lessonId); + } + + hasOrgRole(lesson.getOrganisation().getOrganisationId(), userId, Role.MONITOR, Role.GROUP_MANAGER); + + if (!securityDAO.isSysadmin(userId) && !securityDAO.isLessonMonitor(lessonId, userId)) { + throw new SecurityException("User with ID: " + userId + " is not a monitor in lesson with ID: " + lessonId); + } + } + + @Override + public void checkIsLessonParticipant(Long lessonId, Integer userId) throws SecurityException { + if (lessonId == null) { + throw new SecurityException("Lesson ID is NULL"); + } + if (userId == null) { + throw new SecurityException("User ID is NULL"); + } + + Lesson lesson = (Lesson) securityDAO.find(Lesson.class, lessonId); + if (lesson == null) { + throw new SecurityException("Could not find lesson with ID: " + lessonId); + } + + hasOrgRole(lesson.getOrganisation().getOrganisationId(), userId, Role.LEARNER, Role.MONITOR, Role.GROUP_MANAGER); + + if (!securityDAO.isSysadmin(userId) && !securityDAO.isLessonLearner(lessonId, userId) + && !securityDAO.isLessonMonitor(lessonId, userId)) { + throw new SecurityException("User with ID: " + userId + " is not a learner in lesson with ID: " + lessonId); + } + } + + @Override + public void checkIsSysadmin(Integer userId) { + if (userId == null) { + throw new SecurityException("User ID is NULL"); + } + + if (!securityDAO.isSysadmin(userId)) { + throw new SecurityException("User with ID: " + userId + " is not a sysadmin."); + } + } + + @Override + public void hasOrgRole(Integer orgId, Integer userId, String... roles) throws SecurityException { + if (orgId == null) { + throw new SecurityException("Organisation ID is NULL"); + } + if (userId == null) { + throw new SecurityException("User ID is NULL"); + } + + if (!securityDAO.isSysadmin(userId) && !securityDAO.hasOrgRole(orgId, userId, roles)) { + throw new SecurityException("User with ID: " + userId + " is not any of " + Arrays.toString(roles) + + " in organisation with ID: " + orgId); + } + } + + public void setSecurityDAO(ISecurityDAO securityDAO) { + this.securityDAO = securityDAO; + } +} \ No newline at end of file Index: lams_gradebook/src/java/org/lamsfoundation/lams/gradebook/web/action/GradebookAction.java =================================================================== diff -u -r7e111dfceb5cb118a72e4397389473ab07ad2ca7 -r38b5da8f9b986f835a4dde123bd09954a4b6e171 --- lams_gradebook/src/java/org/lamsfoundation/lams/gradebook/web/action/GradebookAction.java (.../GradebookAction.java) (revision 7e111dfceb5cb118a72e4397389473ab07ad2ca7) +++ lams_gradebook/src/java/org/lamsfoundation/lams/gradebook/web/action/GradebookAction.java (.../GradebookAction.java) (revision 38b5da8f9b986f835a4dde123bd09954a4b6e171) @@ -47,7 +47,10 @@ import org.lamsfoundation.lams.learningdesign.ToolActivity; import org.lamsfoundation.lams.lesson.Lesson; import org.lamsfoundation.lams.lesson.service.ILessonService; +import org.lamsfoundation.lams.security.ISecurityService; +import org.lamsfoundation.lams.security.SecurityException; import org.lamsfoundation.lams.usermanagement.Organisation; +import org.lamsfoundation.lams.usermanagement.Role; import org.lamsfoundation.lams.usermanagement.User; import org.lamsfoundation.lams.usermanagement.dto.UserDTO; import org.lamsfoundation.lams.usermanagement.service.IUserManagementService; @@ -77,6 +80,7 @@ private static IGradebookService gradebookService; private static IUserManagementService userService; private static ILessonService lessonService; + private static ISecurityService securityService; public ActionForward unspecified(ActionMapping mapping, ActionForm form, HttpServletRequest request, HttpServletResponse response) throws Exception { @@ -104,8 +108,6 @@ @SuppressWarnings(value = { "unchecked", "unused" }) public ActionForward getActivityGridData(ActionMapping mapping, ActionForm form, HttpServletRequest request, HttpServletResponse response) throws Exception { - initServices(); - // Getting the params passed in from the jqGrid int page = WebUtil.readIntParam(request, GradebookConstants.PARAM_PAGE); int rowLimit = WebUtil.readIntParam(request, GradebookConstants.PARAM_ROWS); @@ -131,7 +133,7 @@ } } - Lesson lesson = lessonService.getLesson(lessonID); + Lesson lesson = getLessonService().getLesson(lessonID); if (lesson != null) { @@ -141,16 +143,16 @@ // A slightly different list is needed for userview or activity view if (view == GBGridView.MON_USER || view == GBGridView.LRN_ACTIVITY) { //Integer userID = WebUtil.readIntParam(request, GradebookConstants.PARAM_USERID); - User learner = (User) userService.findById(User.class, userID); + User learner = (User) getUserService().findById(User.class, userID); if (learner != null) { - gradebookActivityDTOs = gradebookService.getGBActivityRowsForLearner(lesson, learner); + gradebookActivityDTOs = getGradebookService().getGBActivityRowsForLearner(lesson, learner); } else { // return null and the grid will report the error logger.error("No learner found for: " + userID); return null; } } else if (view == GBGridView.MON_ACTIVITY) { - gradebookActivityDTOs = gradebookService.getGBActivityRowsForLesson(lesson); + gradebookActivityDTOs = getGradebookService().getGBActivityRowsForLesson(lesson); } if (sortBy == null || sortBy.equals("")) { @@ -173,14 +175,13 @@ * * This has three modes: userView, activityView and courseMonitorView * - * User view will get all the learners in a lesson and print their gradebook - * data with their mark for the entire lesson + * User view will get all the learners in a lesson and print their gradebook data with their mark for the entire + * lesson * - * Activity view will take an extra parameter (activityID) and instead show - * the user's mark just for one activity + * Activity view will take an extra parameter (activityID) and instead show the user's mark just for one activity * - * Course monitor view gets the same as the user view, but the link is set - * to the lesson level gradebook instead of learner + * Course monitor view gets the same as the user view, but the link is set to the lesson level gradebook instead of + * learner * * @param mapping * @param form @@ -192,7 +193,6 @@ @SuppressWarnings("unchecked") public ActionForward getUserGridData(ActionMapping mapping, ActionForm form, HttpServletRequest request, HttpServletResponse response) throws Exception { - initServices(); // Getting the params passed in from the jqGrid int page = WebUtil.readIntParam(request, GradebookConstants.PARAM_PAGE); @@ -206,21 +206,29 @@ GBGridView view = GradebookUtil.readGBGridViewParam(request, GradebookConstants.PARAM_VIEW, false); Long lessonID = WebUtil.readLongParam(request, AttributeNames.PARAM_LESSON_ID, true); Integer organisationID = WebUtil.readIntParam(request, AttributeNames.PARAM_ORGANISATION_ID, true); - + UserDTO user = getUser(); + // Get the user gradebook list from the db List gradebookUserDTOs = new ArrayList(); - - //if leesonID is specified show results based on lesson + + // if leesonID is specified show results based on lesson if (lessonID != null) { - - Lesson lesson = lessonService.getLesson(lessonID); + Lesson lesson = getLessonService().getLesson(lessonID); if (lesson == null) { logger.error("No lesson could be found for: " + lessonID); return null; } + try { + getSecurityService().checkIsLessonMonitor(lessonID, user.getUserID()); + } catch (SecurityException e) { + log.error("Cannot get gradebook", e); + response.sendError(HttpServletResponse.SC_FORBIDDEN, "User is not a monitor in the given lesson"); + return null; + } + if (view == GBGridView.MON_USER || view == GBGridView.MON_COURSE) { - gradebookUserDTOs = gradebookService.getGBUserRowsForLesson(lesson); + gradebookUserDTOs = getGradebookService().getGBUserRowsForLesson(lesson); } else if (view == GBGridView.MON_ACTIVITY) { String rowID = WebUtil.readStrParam(request, AttributeNames.PARAM_ACTIVITY_ID); @@ -237,9 +245,9 @@ // Getting the group id if it is there Long groupId = WebUtil.readLongParam(request, GradebookConstants.PARAM_GROUP_ID, true); - Activity activity = gradebookService.getActivityById(activityID); + Activity activity = getGradebookService().getActivityById(activityID); if (activity != null && activity instanceof ToolActivity) { - gradebookUserDTOs = gradebookService.getGBUserRowsForActivity(lesson, (ToolActivity)activity, groupId); + gradebookUserDTOs = getGradebookService().getGBUserRowsForActivity(lesson, (ToolActivity)activity, groupId); } else { // return null and the grid will report an error logger.error("No activity found for: " + activityID); @@ -250,13 +258,21 @@ //if organisationID is specified (but not lessonID) then show results for organisation } else if (organisationID != null) { - Organisation org = (Organisation) userService.findById(Organisation.class, organisationID); + Organisation org = (Organisation) getUserService().findById(Organisation.class, organisationID); if (org == null) { logger.error("No organisation could be found for: " + organisationID); return null; } - gradebookUserDTOs = gradebookService.getGBUserRowsForOrganisation(org); + try { + getSecurityService().hasOrgRole(organisationID, user.getUserID(), Role.MONITOR); + } catch (SecurityException e) { + log.error(e); + response.sendError(HttpServletResponse.SC_FORBIDDEN, "User is not a monitor in the given organisation"); + return null; + } + + gradebookUserDTOs = getGradebookService().getGBUserRowsForOrganisation(org); } else { logger.error("Missing parameters: either lessonID or organisationID should be specified."); @@ -289,8 +305,6 @@ @SuppressWarnings("unchecked") public ActionForward getCourseGridData(ActionMapping mapping, ActionForm form, HttpServletRequest request, HttpServletResponse response) throws Exception { - initServices(); - // Getting the params passed in from the jqGrid int page = WebUtil.readIntParam(request, GradebookConstants.PARAM_PAGE); int rowLimit = WebUtil.readIntParam(request, GradebookConstants.PARAM_ROWS); @@ -302,7 +316,7 @@ String searchString = WebUtil.readStrParam(request, GradebookConstants.PARAM_SEARCH_STRING, true); GBGridView view = GradebookUtil.readGBGridViewParam(request, GradebookConstants.PARAM_VIEW, false); Integer courseID = WebUtil.readIntParam(request, AttributeNames.PARAM_ORGANISATION_ID); - Organisation organisation = (Organisation) userService.findById(Organisation.class, courseID); + Organisation organisation = (Organisation) getUserService().findById(Organisation.class, courseID); // in case of toolbar searching (which uses different parameters than a single field searching) get those parameters if (isSearch && (searchField == null)) { @@ -319,7 +333,7 @@ User user; if (view == GBGridView.MON_USER) { Integer userID = WebUtil.readIntParam(request, GradebookConstants.PARAM_USERID); - user = (User) userService.findById(User.class, userID); + user = (User) getUserService().findById(User.class, userID); } else { user = getRealUser(); } @@ -330,7 +344,7 @@ logger.error("Error: request for course gradebook data with null course or user. CourseID: " + courseID); return null; } - List gradebookLessonDTOs = gradebookService.getGBLessonRows(organisation, user, viewer, view); + List gradebookLessonDTOs = getGradebookService().getGBLessonRows(organisation, user, viewer, view); if (sortBy == null) { sortBy = GradebookConstants.PARAM_ID; @@ -358,17 +372,15 @@ @SuppressWarnings("unchecked") public ActionForward getLessonMarkAggregate(ActionMapping mapping, ActionForm form, HttpServletRequest request, HttpServletResponse response) throws Exception { - initServices(); - Long lessonID = WebUtil.readLongParam(request, AttributeNames.PARAM_LESSON_ID); Integer userID = WebUtil.readIntParam(request, GradebookConstants.PARAM_USERID); - Lesson lesson = lessonService.getLesson(lessonID); - User learner = (User) userService.findById(User.class, userID); + Lesson lesson = getLessonService().getLesson(lessonID); + User learner = (User) getUserService().findById(User.class, userID); if (lesson != null && learner != null) { - GradebookUserLesson lessonMark = gradebookService.getGradebookUserLesson(lessonID, userID); + GradebookUserLesson lessonMark = getGradebookService().getGradebookUserLesson(lessonID, userID); writeResponse(response, CONTENT_TYPE_TEXT_PLAIN, ENCODING_UTF8, GradebookUtil.niceFormatting(lessonMark.getMark())); } else { // Grid will handle error, just log and return null @@ -391,8 +403,6 @@ @SuppressWarnings("unchecked") public ActionForward getActivityMarkAverage(ActionMapping mapping, ActionForm form, HttpServletRequest request, HttpServletResponse response) throws Exception { - initServices(); - String rowID = WebUtil.readStrParam(request, AttributeNames.PARAM_ACTIVITY_ID); Long activityID = null; @@ -407,10 +417,10 @@ activityID = Long.parseLong(rowID); } - Activity activity = gradebookService.getActivityById(activityID); + Activity activity = getGradebookService().getActivityById(activityID); if (activity != null) { - Double averageMark = gradebookService.getAverageMarkForActivity(activityID, groupID); + Double averageMark = getGradebookService().getAverageMarkForActivity(activityID, groupID); if (averageMark != null) { writeResponse(response, CONTENT_TYPE_TEXT_PLAIN, ENCODING_UTF8, GradebookUtil.niceFormatting(averageMark)); @@ -437,13 +447,11 @@ @SuppressWarnings("unchecked") public ActionForward getLessonMarkAverage(ActionMapping mapping, ActionForm form, HttpServletRequest request, HttpServletResponse response) throws Exception { - initServices(); - Long lessonID = WebUtil.readLongParam(request, AttributeNames.PARAM_LESSON_ID); - Lesson lesson = lessonService.getLesson(lessonID); + Lesson lesson = getLessonService().getLesson(lessonID); if (lesson != null) { - Double averageMark = gradebookService.getAverageMarkForLesson(lessonID); + Double averageMark = getGradebookService().getAverageMarkForLesson(lessonID); if (averageMark != null) { writeResponse(response, CONTENT_TYPE_TEXT_PLAIN, ENCODING_UTF8, GradebookUtil.niceFormatting(averageMark)); @@ -473,12 +481,6 @@ } } - private void initServices() { - getUserService(); - getLessonService(); - getGradebookService(); - } - private IUserManagementService getUserService() { if (userService == null) { WebApplicationContext ctx = WebApplicationContextUtils.getRequiredWebApplicationContext(getServlet() @@ -506,4 +508,13 @@ return gradebookService; } + private ISecurityService getSecurityService() { + if (GradebookAction.securityService == null) { + WebApplicationContext webContext = WebApplicationContextUtils.getRequiredWebApplicationContext(getServlet() + .getServletContext()); + GradebookAction.securityService = (ISecurityService) webContext.getBean("securityService"); + } + + return GradebookAction.securityService; + } } Index: lams_learning/src/java/org/lamsfoundation/lams/learning/export/service/ExportPortfolioServiceProxy.java =================================================================== diff -u -r3efaca40454f0c4c55a2d380a926b92e140f58cf -r38b5da8f9b986f835a4dde123bd09954a4b6e171 --- lams_learning/src/java/org/lamsfoundation/lams/learning/export/service/ExportPortfolioServiceProxy.java (.../ExportPortfolioServiceProxy.java) (revision 3efaca40454f0c4c55a2d380a926b92e140f58cf) +++ lams_learning/src/java/org/lamsfoundation/lams/learning/export/service/ExportPortfolioServiceProxy.java (.../ExportPortfolioServiceProxy.java) (revision 38b5da8f9b986f835a4dde123bd09954a4b6e171) @@ -27,6 +27,7 @@ import javax.servlet.ServletContext; import org.lamsfoundation.lams.lesson.service.ILessonService; +import org.lamsfoundation.lams.security.ISecurityService; import org.springframework.web.context.WebApplicationContext; import org.springframework.web.context.support.WebApplicationContextUtils; @@ -50,4 +51,9 @@ public static final ILessonService getLessonService(ServletContext servletContext) { return (ILessonService) ExportPortfolioServiceProxy.getDomainService(servletContext, "lessonService"); } + + + public static final ISecurityService getSecurityService(ServletContext servletContext) { + return (ISecurityService) ExportPortfolioServiceProxy.getDomainService(servletContext, "securityService"); + } } \ No newline at end of file Index: lams_learning/src/java/org/lamsfoundation/lams/learning/export/web/action/MainExportServlet.java =================================================================== diff -u -r3efaca40454f0c4c55a2d380a926b92e140f58cf -r38b5da8f9b986f835a4dde123bd09954a4b6e171 --- lams_learning/src/java/org/lamsfoundation/lams/learning/export/web/action/MainExportServlet.java (.../MainExportServlet.java) (revision 3efaca40454f0c4c55a2d380a926b92e140f58cf) +++ lams_learning/src/java/org/lamsfoundation/lams/learning/export/web/action/MainExportServlet.java (.../MainExportServlet.java) (revision 38b5da8f9b986f835a4dde123bd09954a4b6e171) @@ -54,8 +54,10 @@ import org.lamsfoundation.lams.learning.export.Portfolio; import org.lamsfoundation.lams.learning.export.service.ExportPortfolioServiceProxy; import org.lamsfoundation.lams.learning.export.service.IExportPortfolioService; +import org.lamsfoundation.lams.lesson.LearnerProgress; import org.lamsfoundation.lams.lesson.Lesson; import org.lamsfoundation.lams.lesson.service.ILessonService; +import org.lamsfoundation.lams.security.ISecurityService; import org.lamsfoundation.lams.tool.ToolAccessMode; import org.lamsfoundation.lams.usermanagement.User; import org.lamsfoundation.lams.usermanagement.dto.UserDTO; @@ -111,17 +113,33 @@ IExportPortfolioService exportService = ExportPortfolioServiceProxy.getExportPortfolioService(this .getServletContext()); ILessonService lessonService = ExportPortfolioServiceProxy.getLessonService(this.getServletContext()); + ISecurityService securityService = ExportPortfolioServiceProxy.getSecurityService(this + .getServletContext()); Lesson lesson = lessonService.getLesson(lessonID); if (mode.equals(ToolAccessMode.LEARNER.toString())) { if (!lesson.getLearnerExportAvailable()) { - throw new ExportPortfolioException("This lesson does not allow export portfolio for learners"); + throw new ExportPortfolioException("Lesson with ID: " + lesson.getLessonId() + + " does not allow export portfolio for learners"); } ToolAccessMode accessMode = ToolAccessMode.TEACHER.toString().equals(role) ? ToolAccessMode.TEACHER : null; - boolean canExport = isPartOfClass(lesson, currentUserId, accessMode != null); - if (!canExport) { - throw new ExportPortfolioException("User " + currentUserId + " is not a participant in lesson " - + lessonID + " and may not export portfolio"); + + try { + if (accessMode == null) { + securityService.checkIsLessonLearner(lesson.getLessonId(), currentUserId); + LearnerProgress learnerProgress = lessonService.getUserProgressForLesson(currentUserId, + lesson.getLessonId()); + if (learnerProgress == null || !learnerProgress.isComplete()) { + throw new ExportPortfolioException("Learner with ID: " + currentUserId + + " has not finished lesson with ID: " + lesson.getLessonId()); + } + } else { + securityService.checkIsLessonMonitor(lesson.getLessonId(), currentUserId); + } + } catch (SecurityException e) { + log.error("Cannot export portfolion", e); + response.sendError(HttpServletResponse.SC_FORBIDDEN, "The user is not a monitor in the lesson"); + return; } portfolios = exportService.exportPortfolioForStudent(userIdParam == null ? currentUserId : userIdParam, @@ -131,10 +149,12 @@ exportFilename = ExportPortfolioConstants.EXPORT_LEARNER_PREFIX + " " + portfolios.getLessonName() + " " + learnerLogin + ".zip"; } else if (mode.equals(ToolAccessMode.TEACHER.toString())) { - boolean canExport = isPartOfClass(lesson, currentUserId, true); - if (!canExport) { - throw new ExportPortfolioException("User " + currentUserId + " is not a participant in lesson " - + lessonID + " and may not export portfolio"); + try { + securityService.checkIsLessonMonitor(lesson.getLessonId(), currentUserId); + } catch (SecurityException e) { + log.error("Cannot export portfolion", e); + response.sendError(HttpServletResponse.SC_FORBIDDEN, "The user is not a monitor in the lesson"); + return; } // done in the monitoring environment @@ -301,23 +321,4 @@ MainExportServlet.log.error("Unable to correct imagefolder links in file " + filename, e); } } - - private boolean isPartOfClass(Lesson lesson, Integer userId, boolean isTeacher) { - Set users = null; - if (isTeacher) { - users = lesson.getLessonClass().getStaffGroup().getUsers(); - } else { - users = lesson.getLessonClass().getLearnersGroup().getUsers(); - } - - // slightly easier than getting user from some other service and using collection methods, like contains() - boolean result = false; - for (User user : users) { - if (user.getUserId().equals(userId)) { - result = true; - break; - } - } - return result; - } } \ No newline at end of file Index: lams_monitoring/src/java/org/lamsfoundation/lams/monitoring/web/MonitoringAction.java =================================================================== diff -u -r74a09b6237dfef4cb2aab41ce8918c45a5cab34f -r38b5da8f9b986f835a4dde123bd09954a4b6e171 --- lams_monitoring/src/java/org/lamsfoundation/lams/monitoring/web/MonitoringAction.java (.../MonitoringAction.java) (revision 74a09b6237dfef4cb2aab41ce8918c45a5cab34f) +++ lams_monitoring/src/java/org/lamsfoundation/lams/monitoring/web/MonitoringAction.java (.../MonitoringAction.java) (revision 38b5da8f9b986f835a4dde123bd09954a4b6e171) @@ -74,6 +74,8 @@ import org.lamsfoundation.lams.monitoring.dto.ContributeActivityDTO; import org.lamsfoundation.lams.monitoring.service.IMonitoringService; import org.lamsfoundation.lams.monitoring.service.MonitoringServiceProxy; +import org.lamsfoundation.lams.security.ISecurityService; +import org.lamsfoundation.lams.security.SecurityException; import org.lamsfoundation.lams.timezone.service.ITimezoneService; import org.lamsfoundation.lams.tool.exception.LamsToolServiceException; import org.lamsfoundation.lams.usermanagement.Organisation; @@ -141,7 +143,10 @@ private static ITimezoneService timezoneService; private static ILessonService lessonService; + + private static ISecurityService securityService; + private Integer getUserId() { HttpSession ss = SessionManager.getSession(); UserDTO user = (UserDTO) ss.getAttribute(AttributeNames.USER); @@ -842,11 +847,15 @@ DateFormat sfm = new SimpleDateFormat("yyyyMMdd_HHmmss"); lessonDTO.setCreateDateTimeStr(sfm.format(lessonDTO.getCreateDateTime())); } + + try { + getSecurityService().checkIsLessonMonitor(lessonId, user.getUserID()); + } catch (SecurityException e) { + log.error("Cannot monitor lesson", e); + response.sendError(HttpServletResponse.SC_FORBIDDEN, "User is not a monitor in the given lesson"); + return null; + } - IMonitoringService monitoringService = MonitoringServiceProxy.getMonitoringService(getServlet() - .getServletContext()); - monitoringService.checkOwnerOrStaffMember(user.getUserID(), lessonId, "monitor lesson"); - // should info box on Sequence tab be displayed? Short sequenceTabInfoShowCount = (Short) ss.getAttribute("sequenceTabInfoShowCount"); if (sequenceTabInfoShowCount == null) { @@ -1203,6 +1212,15 @@ } return MonitoringAction.lessonService; } + + private ISecurityService getSecurityService() { + if (MonitoringAction.securityService == null) { + WebApplicationContext ctx = WebApplicationContextUtils.getRequiredWebApplicationContext(getServlet() + .getServletContext()); + MonitoringAction.securityService = (ISecurityService) ctx.getBean("securityService"); + } + return MonitoringAction.securityService; + } /** * Set whether or not the export portfolio button is available in learner. Expects parameters lessonID and