/********************************************************************************** * $URL: https://source.sakaiproject.org/svn/tool/trunk/tool-tool/su/src/java/org/sakaiproject/tool/su/SuTool.java $ * $Id: SuTool.java 130020 2013-09-30 13:19:20Z holladay@longsight.com $ *********************************************************************************** * * Copyright (c) 2005, 2006, 2007, 2008 The Sakai Foundation * * 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.su; import java.lang.reflect.Method; import java.util.List; import java.util.Vector; import javax.faces.application.FacesMessage; import javax.faces.context.FacesContext; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; import org.sakaiproject.authz.api.AuthzGroupService; import org.sakaiproject.authz.api.SecurityService; import org.sakaiproject.component.api.ServerConfigurationService; import org.sakaiproject.component.cover.ComponentManager; import org.sakaiproject.event.api.Event; import org.sakaiproject.event.api.EventTrackingService; import org.sakaiproject.event.api.UsageSessionService; import org.sakaiproject.site.api.Site; import org.sakaiproject.site.api.SiteService.SelectionType; import org.sakaiproject.tool.api.Session; import org.sakaiproject.tool.api.SessionManager; import org.sakaiproject.user.api.User; import org.sakaiproject.user.api.UserDirectoryService; import org.sakaiproject.user.api.UserNotDefinedException; import org.sakaiproject.util.RequestFilter; import org.sakaiproject.util.ResourceLoader; /** * @author zach.thomas@txstate.edu */ public class SuTool { private static final long serialVersionUID = 1L; /** Our log (commons). */ private static Log M_log = LogFactory.getLog(SuTool.class); protected static final String SU_BECOME_USER = "su.become"; protected static final String SU_VIEW_USER = "su.view"; ResourceLoader msgs = new ResourceLoader("tool-tool-su"); // Service instance variables private AuthzGroupService M_authzGroupService = org.sakaiproject.authz.cover.AuthzGroupService .getInstance(); private UserDirectoryService M_uds = org.sakaiproject.user.cover.UserDirectoryService.getInstance(); private SecurityService M_security = org.sakaiproject.authz.cover.SecurityService.getInstance(); private SessionManager M_session = org.sakaiproject.tool.cover.SessionManager.getInstance(); private ServerConfigurationService M_config = org.sakaiproject.component.cover.ServerConfigurationService .getInstance(); private EventTrackingService M_event_service = org.sakaiproject.event.cover.EventTrackingService.getInstance(); // getters for these vars private String username; private String validatedUserId; private String validatedUserEid; private User userinfo; private boolean allowed = false; // internal only vars private String message = ""; private boolean confirm = false; private Class delegatedAccessLogicHelper = null; private Object delegatedAccessLogic = null; private Method hasDelegatedAccessNodes = null; private Method initializeDelegatedAccessSession = null; private Method isUserAllowBecomeUser = null; private boolean allowDelegatedAccessBecomeUser = false; // base constructor public SuTool() { try{ delegatedAccessLogicHelper = RequestFilter.class.getClassLoader().loadClass("org.sakaiproject.delegatedaccess.logic.ProjectLogic"); delegatedAccessLogic = ComponentManager.get(delegatedAccessLogicHelper); hasDelegatedAccessNodes = delegatedAccessLogicHelper.getMethod("hasDelegatedAccessNodes", new Class[]{String.class}); initializeDelegatedAccessSession = delegatedAccessLogicHelper.getMethod("initializeDelegatedAccessSession", new Class[]{}); isUserAllowBecomeUser = delegatedAccessLogicHelper.getMethod("isUserAllowBecomeUser", new Class[]{String.class, String.class}); //only allow become user logic for Delegated Access if the allowBecomeUser method exist if(isUserAllowBecomeUser != null){ allowDelegatedAccessBecomeUser = true; } }catch(Exception e){ M_log.info("Could not inject Delegated Access logic bean, either doesn't exist or there is a bigger problem"); } } /** * Functions */ public String su() { Session sakaiSession = M_session.getCurrentSession(); FacesContext fc = FacesContext.getCurrentInstance(); userinfo = null; message = ""; try { // try with the user id userinfo = M_uds.getUser(username.trim()); validatedUserId = userinfo.getId(); validatedUserEid = userinfo.getEid(); } catch (UserNotDefinedException e) { try { // try with the user eid userinfo = M_uds.getUserByEid(username.trim()); validatedUserId = userinfo.getId(); validatedUserEid = userinfo.getEid(); } catch (UserNotDefinedException ee) { message = msgs.getString("no_such_user") + ": " + username; fc.addMessage("su", new FacesMessage(FacesMessage.SEVERITY_ERROR, message, message + ":" + ee)); M_log.warn("[SuTool] Exception: " + message); confirm = false; return "error"; } } if (!getAllowed(userinfo)) { confirm = false; userinfo = null; return "unauthorized"; } // don't try to become yourself if (sakaiSession.getUserEid().equals(validatedUserEid)) { confirm = false; message = msgs.getFormattedMessage("already_that_user", new Object[] {username}); fc.addMessage("su", new FacesMessage(FacesMessage.SEVERITY_ERROR, message, message)); M_log.warn("[SuTool] Exception: " + message); confirm = false; return "error"; } if (!confirm) { message = msgs.getString("displaying_info_for") + ": " + validatedUserEid; fc.addMessage("su", new FacesMessage(FacesMessage.SEVERITY_INFO, message, message + ":" + userinfo.getDisplayName())); Event event = M_event_service.newEvent(SU_VIEW_USER, M_uds.userReference(validatedUserId), false); M_event_service.post(event); return "unconfirmed"; } // set the session user from the value supplied in the form message = "Username " + sakaiSession.getUserEid() + " becoming " + validatedUserEid; M_log.info("[SuTool] " + message); message = msgs.getString("title"); fc.addMessage("su", new FacesMessage(FacesMessage.SEVERITY_INFO, message, message + ": " + userinfo.getDisplayName())); // while keeping the official usage session under the real user id, switch over everything else to be the SU'ed user // Modeled on UsageSession's logout() and login() // Post an event Event event = M_event_service.newEvent(SU_BECOME_USER, M_uds.userReference(validatedUserId), false); M_event_service.post(event); // logout - clear, but do not invalidate, preserve the usage session's current session Vector saveAttributes = new Vector(); saveAttributes.add(UsageSessionService.USAGE_SESSION_KEY); saveAttributes.add(UsageSessionService.SAKAI_CSRF_SESSION_ATTRIBUTE); sakaiSession.clearExcept(saveAttributes); // login - set the user id and eid into session, and refresh this user's authz information sakaiSession.setUserId(validatedUserId); sakaiSession.setUserEid(validatedUserEid); M_authzGroupService.refreshUser(validatedUserId); //if DA is present, initialize the user's DA settings: if(initializeDelegatedAccessSession != null){ try{ initializeDelegatedAccessSession.invoke(delegatedAccessLogic, new Object[]{}); }catch(Exception e){ M_log.error(e.getMessage(), e); } } return "redirect"; } // simple way to support 2 buttons that do almost the same thing public String confirm() { confirm = true; return su(); } /** * Specialized Getters */ public boolean getAllowed() { Session sakaiSession = M_session.getCurrentSession(); FacesContext fc = FacesContext.getCurrentInstance(); //allow the user to access the tool if they are either a DA user or Super Admin if (!M_security.isSuperUser() && sakaiSession.getAttribute("delegatedaccess.accessmapflag") != null) { message = msgs.getString("unauthorized") + " " + sakaiSession.getUserId(); M_log.error("[SuTool] Fatal Error: " + message); fc.addMessage("allowed", new FacesMessage(FacesMessage.SEVERITY_FATAL, message, message)); allowed = false; } else { allowed = true; } return allowed; } public boolean getAllowed(User userinfo) { Session sakaiSession = M_session.getCurrentSession(); FacesContext fc = FacesContext.getCurrentInstance(); if (!M_security.isSuperUser()) { //current user is not a super admin, let's make sure they are not becoming a user they are not allowed to become if(!M_security.isSuperUser(userinfo.getId())){ //Delegated Access check //is the user a DA user? If so, check their access as well as the become user accsess, otherwise, deny if(allowDelegatedAccessBecomeUser && getDelegatedAccessUser()){ //this flag is only set when a user is a DA user //now check if the become user is a DA user, if so, then do not allow a DA user to become another DA user if(!getDelegatedAccessUser(userinfo.getId())){ //the user is not a DA user, so lets check if the user is a member of any sites that the //current user has DA access to visit String currentUserId = sakaiSession.getUserId(); String currentUserEid = sakaiSession.getUserEid(); List siteList = null; try{ sakaiSession.setUserId(userinfo.getId()); sakaiSession.setUserEid(userinfo.getEid()); siteList = org.sakaiproject.site.cover.SiteService.getSites(SelectionType.ACCESS, null, null, null, null, null); }catch(Exception e){ M_log.info(e.getMessage(), e); }finally{ sakaiSession.setUserId(currentUserId); sakaiSession.setUserEid(currentUserEid); } if(siteList != null && siteList.size() > 0){ boolean anyAccess = false; try{ for(Site site : (List<Site>) siteList){ Object val = isUserAllowBecomeUser.invoke(delegatedAccessLogic, new Object[]{sakaiSession.getUserId(), site.getReference()}); if(val != null && val instanceof Boolean && ((Boolean) val)){ //this user has site access and "become user" permission for this site anyAccess = true; break; } } }catch(Exception e){ M_log.info(e.getMessage(), e); } if(anyAccess){ //this means that the current user has access to a site that the userinfo user is a member of, so //let them become this user allowed = true; }else{ //current user can't become a user that isn't within their DA access message = msgs.getString("unauthorized_danoaccess"); M_log.error("[SuTool] Fatal Error: " + message + " " + sakaiSession.getUserId()); fc.addMessage("allowed", new FacesMessage(FacesMessage.SEVERITY_FATAL, message, message)); allowed = false; } }else{ //the userinfo user either doesn't have any sites to access or there was an error message = msgs.getString("unauthorized_danoaccess"); M_log.info("[SuTool] Fatal Error: " + message + " " + sakaiSession.getUserId()); fc.addMessage("allowed", new FacesMessage(FacesMessage.SEVERITY_FATAL, message, message)); allowed = false; } }else{ //current user is trying to become a DA user, which isn't allowed message = msgs.getString("unauthorized_da"); M_log.info("[SuTool] Fatal Error: " + message + " " + sakaiSession.getUserId()); fc.addMessage("allowed", new FacesMessage(FacesMessage.SEVERITY_FATAL, message, message)); allowed = false; } }else{ //current user is not a DA user and not a super user, so they have no access message = msgs.getString("unauthorized"); M_log.info("[SuTool] Fatal Error: " + message + " " + sakaiSession.getUserId()); fc.addMessage("allowed", new FacesMessage(FacesMessage.SEVERITY_FATAL, message, message)); allowed = false; } }else{ //non admin users can't become an admin user message = msgs.getString("unauthorized_superuser"); M_log.info("[SuTool] Fatal Error: " + message + " " + sakaiSession.getUserId()); fc.addMessage("allowed", new FacesMessage(FacesMessage.SEVERITY_FATAL, message, message)); allowed = false; } } else { allowed = true; } return allowed; } /** * Basic Getters and setters */ public String getUsername() { return username; } public String getPortalUrl() { return M_config.getPortalUrl(); } public void setUsername(String username) { this.username = username; } public User getUserinfo() { return userinfo; } public void setUserinfo(User userinfo) { this.userinfo = userinfo; } public String getMessage(){ return message; } public Boolean getSuperUser(){ return M_security.isSuperUser(); } public Boolean getDelegatedAccessUser(){ return getDelegatedAccessUser(M_session.getCurrentSessionUserId()); } public Boolean getDelegatedAccessUser(String userId){ if(hasDelegatedAccessNodes != null){ try { Object hasAccess = hasDelegatedAccessNodes.invoke(delegatedAccessLogic, new Object[]{userId}); if(hasAccess != null && hasAccess instanceof Boolean && ((Boolean) hasAccess)){ return Boolean.TRUE; } } catch (Exception e){ M_log.error(e.getMessage(), e); } } return Boolean.FALSE; } }