package org.sakaiproject.delegatedaccess.logic; import java.util.ArrayList; import java.util.Arrays; import java.util.Collection; import java.util.Collections; import java.util.Comparator; import java.util.HashMap; import java.util.HashSet; import java.util.List; import java.util.Map; import java.util.Set; import lombok.Getter; import lombok.Setter; import org.apache.log4j.Logger; import org.sakaiproject.authz.api.AuthzGroup; import org.sakaiproject.authz.api.AuthzGroupService; import org.sakaiproject.authz.api.AuthzPermissionException; import org.sakaiproject.authz.api.GroupNotDefinedException; import org.sakaiproject.authz.api.Member; import org.sakaiproject.authz.api.Role; import org.sakaiproject.authz.api.RoleAlreadyDefinedException; import org.sakaiproject.authz.api.SecurityAdvisor; import org.sakaiproject.authz.api.SecurityService; import org.sakaiproject.component.api.ServerConfigurationService; import org.sakaiproject.coursemanagement.api.AcademicSession; import org.sakaiproject.coursemanagement.api.CourseManagementService; import org.sakaiproject.delegatedaccess.dao.DelegatedAccessDao; import org.sakaiproject.delegatedaccess.util.DelegatedAccessConstants; import org.sakaiproject.email.api.EmailService; import org.sakaiproject.entity.api.Entity; import org.sakaiproject.entity.api.EntityManager; import org.sakaiproject.entity.api.Reference; import org.sakaiproject.event.api.EventTrackingService; import org.sakaiproject.exception.IdUnusedException; import org.sakaiproject.exception.PermissionException; import org.sakaiproject.javax.PagingPosition; import org.sakaiproject.site.api.Site; import org.sakaiproject.site.api.SiteService; import org.sakaiproject.site.api.SiteService.SelectionType; import org.sakaiproject.site.api.SiteService.SortType; import org.sakaiproject.tool.api.Session; import org.sakaiproject.tool.api.SessionManager; import org.sakaiproject.tool.api.Tool; import org.sakaiproject.tool.api.ToolManager; import org.sakaiproject.user.api.User; import org.sakaiproject.user.api.UserDirectoryService; import org.sakaiproject.user.api.UserNotDefinedException; import javax.mail.MessagingException; import javax.mail.internet.InternetAddress; /** * Implementation of our SakaiProxy API * * @author Bryan Holladay (holladay@longsight.com) * */ public class SakaiProxyImpl implements SakaiProxy { private static final Logger log = Logger.getLogger(SakaiProxyImpl.class); @Getter @Setter private AuthzGroupService authzGroupService; @Getter @Setter private SessionManager sessionManager; @Getter @Setter private UserDirectoryService userDirectoryService; @Getter @Setter private SecurityService securityService; @Getter @Setter private EventTrackingService eventTrackingService; @Getter @Setter private ServerConfigurationService serverConfigurationService; @Getter @Setter private SiteService siteService; @Getter @Setter private EntityManager entityManager; @Getter @Setter private ToolManager toolManager; @Getter @Setter private DelegatedAccessDao dao; @Getter @Setter private CourseManagementService cms; @Getter @Setter private EmailService emailService; //cached variables: private List<String[]> terms; /** * init - perform any actions required here for when this bean starts up */ public void init() { } /** * {@inheritDoc} */ public String getCurrentUserId() { return sessionManager.getCurrentSessionUserId(); } /** * {@inheritDoc} */ public boolean isSuperUser() { return securityService.isSuperUser(); } /** * {@inheritDoc} */ public Session getCurrentSession(){ return sessionManager.getCurrentSession(); } /** * {@inheritDoc} */ public List<Site> getAllSites(){ return siteService.getSites(SelectionType.NON_USER, null, null, null, null, null); } /** * {@inheritDoc} */ public List<Site> getAllSitesByPages(Map<String, String> propsMap, int page, int pageMax, boolean orderByModifiedDate){ PagingPosition pp = new PagingPosition(page, pageMax); return siteService.getSites(SelectionType.NON_USER, null, null, propsMap, orderByModifiedDate ? SortType.MODIFIED_ON_DESC : null, pp); } /** * {@inheritDoc} */ public void postEvent(String event,String reference,boolean modify) { eventTrackingService.post(eventTrackingService.newEvent(event,reference,modify)); } public Set<Tool> getAllTools(){ Set<Tool> toolSet = new HashSet<Tool>(); String[] toolsList = null; String siteType = serverConfigurationService.getString(DelegatedAccessConstants.PROP_TOOL_LIST_TEMPLATE); if(siteType != null && !"".equals(siteType)){ toolSet = toolManager.findTools(new HashSet<String>(Arrays.asList(siteType)), null); } if(toolSet.size() == 0){ toolsList = serverConfigurationService.getStrings(DelegatedAccessConstants.PROP_TOOL_LIST); if(toolsList != null && toolsList.length > 0){ for(String toolId : toolsList){ Tool tool = toolManager.getTool(toolId); if(tool != null){ toolSet.add(tool); } } } } if(toolSet.size() == 0){ return toolManager.findTools(new HashSet<String>(), null); }else{ return toolSet; } } public Tool getTool(String toolId){ return toolManager.getTool(toolId); } public String[] getHomeTools(){ return serverConfigurationService.getStrings(DelegatedAccessConstants.PROPERTIES_HOME_TOOLS); } /** * {@inheritDoc} */ public String getSkinRepoProperty(){ return serverConfigurationService.getString("skin.repo"); } /** * {@inheritDoc} */ public String getToolSkinCSS(String skinRepo){ String skin = siteService.findTool(sessionManager.getCurrentToolSession().getPlacementId()).getSkin(); if(skin == null) { skin = serverConfigurationService.getString("skin.default"); } return skinRepo + "/" + skin + "/tool.css"; } /** * {@inheritDoc} */ public List<User> searchUsers(String search) { List<User> returnList = new ArrayList<User>(); returnList.addAll(userDirectoryService.searchExternalUsers(search, -1, -1)); returnList.addAll(userDirectoryService.searchUsers(search, 1, Integer.MAX_VALUE)); return returnList; } /** * {@inheritDoc} */ public User getUser(String id){ try { return userDirectoryService.getUser(id); } catch (UserNotDefinedException e) { return null; } } /** * {@inheritDoc} */ public User getUserByEid(String eid){ try { return userDirectoryService.getUserByEid(eid); } catch (UserNotDefinedException e) { return null; } } /** * {@inheritDoc} */ public Site getSiteByRef(String siteRef){ Site site = null; Reference r = entityManager.newReference(siteRef); if(r.getType().equals(SiteService.APPLICATION_ID)){ try { site = siteService.getSite(r.getId()); } catch (IdUnusedException e) { log.error(e.getMessage(), e); } } return site; } /** * {@inheritDoc} */ public Site getSiteById(String siteId){ Site site = null; try { site = siteService.getSite(siteId); } catch (IdUnusedException e) { } return site; } /** * {@inheritDoc} */ public void saveSite(Site site){ SecurityAdvisor yesMan = new SecurityAdvisor() { public SecurityAdvice isAllowed(String userId, String function, String reference) { return SecurityAdvice.ALLOWED; } }; try { securityService.pushAdvisor(yesMan); siteService.save(site); } catch (IdUnusedException e) { log.error(e.getMessage(), e); } catch (PermissionException e) { log.error(e.getMessage(), e); }finally{ securityService.popAdvisor(yesMan); } } /** * {@inheritDoc} */ public String getRootName(){ return serverConfigurationService.getString( DelegatedAccessConstants.HIERARCHY_ROOT_TITLE_PROPERTY, serverConfigurationService.getString("ui.service", DelegatedAccessConstants.HIERARCHY_ROOT_TITLE_DEFAULT)); } /** * {@inheritDoc} */ public String[] getServerConfigurationStrings(String property){ return serverConfigurationService.getStrings(property); } /** * {@inheritDoc} */ public Map<String, List<String>> getSiteTemplates(){ Map<String, List<String>> returnList = new HashMap<String, List<String>>(); for(AuthzGroup group : authzGroupService.getAuthzGroups("!site.", new PagingPosition(1, DelegatedAccessConstants.SEARCH_RESULTS_MAX))){ returnList.put(group.getId(), getFilteredRoles(group, null)); } return returnList; } public Map<String, List<String>> getShoppingRealmOptions(){ String[] authzGroups = serverConfigurationService.getStrings(DelegatedAccessConstants.PROPERTIES_REALM_OPTIONS_SHOPPING); if(authzGroups != null && authzGroups.length != 0){ String[] filterRoles = serverConfigurationService.getStrings(DelegatedAccessConstants.PROPERTIES_ROLE_OPTIONS_SHOPPING); return getGroupsById(authzGroups, filterRoles); }else{ return getSiteTemplates(); } } public Map<String, List<String>> getDelegatedAccessRealmOptions(){ String[] authzGroups = serverConfigurationService.getStrings(DelegatedAccessConstants.PROPERTIES_REALM_OPTIONS_ACCESS); if(authzGroups != null && authzGroups.length != 0){ String[] filterRoles = serverConfigurationService.getStrings(DelegatedAccessConstants.PROPERTIES_ROLE_OPTIONS_ACCESS); return getGroupsById(authzGroups, filterRoles); }else{ return getSiteTemplates(); } } private Map<String, List<String>> getGroupsById(String[] groups, String[] filterRoles){ Map<String, List<String>> returnList = new HashMap<String, List<String>>(); for(int i = 0; i < groups.length; i++){ try { AuthzGroup group = authzGroupService.getAuthzGroup(groups[i]); if(group != null){ returnList.put(group.getId(), getFilteredRoles(group, filterRoles)); } } catch (GroupNotDefinedException e) { log.error(e.getMessage(), e); } } return returnList; } /** * this will remove any role that isn't in the list of roles passed in. * If roles is null or empty, it will not filter any roles * * @param groups * @param roles * @return */ private List<String> getFilteredRoles(AuthzGroup group, String[] filterRoles){ List<String> returnRoles = new ArrayList<String>(); if(group != null){ for(Role role : group.getRoles()){ if(filterRoles != null){ for(int i = 0; i < filterRoles.length; i++){ if(role.getId().equals(filterRoles[i])){ returnRoles.add(role.getId()); break; } } }else{ returnRoles.add(role.getId()); } } } return returnRoles; } /** * {@inheritDoc} */ public void refreshCurrentUserAuthz(){ authzGroupService.refreshUser(getCurrentUserId()); } public Set<String> getUserMembershipForCurrentUser(){ Set<String> returnSet = new HashSet<String>(); for(Site site: siteService.getSites(SelectionType.ACCESS, null, null, null, SortType.NONE, null)){ returnSet.add(site.getReference()); } return returnSet; } public List<Site> getSites(SelectionType type, String search, Map<String, String> propsMap){ return siteService.getSites(type, null, search, propsMap, SortType.NONE, null); } public boolean isShoppingTool(){ return "sakai.delegatedaccess.shopping".equals(toolManager.getCurrentPlacement().getToolId()); } /** * {@inheritDoc} */ public AuthzGroup getAuthzGroup(String siteId){ AuthzGroup group = null; try { group = authzGroupService.getAuthzGroup(siteId); } catch (GroupNotDefinedException e) { log.error(e.getMessage(), e); } return group; } /** * {@inheritDoc} */ public void removeRoleFromAuthzGroup(AuthzGroup group, Role role) { // Cheating to become admin in order to modify authz groups SecurityAdvisor yesMan = new SecurityAdvisor() { public SecurityAdvice isAllowed(String userId, String function, String reference) { return SecurityAdvice.ALLOWED; } }; try { group.removeRole(role.getId()); securityService.pushAdvisor(yesMan); authzGroupService.save(group); } catch (AuthzPermissionException e) { log.error(e.getMessage(), e); } catch (GroupNotDefinedException e) { log.error(e.getMessage(), e); } finally { securityService.popAdvisor(yesMan); } } /** * {@inheritDoc} */ public void copyNewRole(String siteRef, String copyRealm, String copyRole, String newRole){ // Cheating to become admin in order to modify authz groups SecurityAdvisor yesMan = new SecurityAdvisor() { public SecurityAdvice isAllowed(String userId, String function, String reference) { return SecurityAdvice.ALLOWED; } }; try { // become admin securityService.pushAdvisor(yesMan); // Get the source realm and role AuthzGroup sourceGroup = authzGroupService.getAuthzGroup(copyRealm); Role copyFromRole = sourceGroup.getRole(copyRole); // Copy the role to the dest role AuthzGroup destGroup = authzGroupService.getAuthzGroup(siteRef); destGroup.removeRole(newRole); destGroup.addRole(newRole, copyFromRole); authzGroupService.save(destGroup); } catch (RoleAlreadyDefinedException e) { log.error(e.getMessage(), e); // wtf? } catch (GroupNotDefinedException e) { log.error(e.getMessage(), e); } catch (AuthzPermissionException e) { log.error(e.getMessage(), e); } finally { securityService.popAdvisor(yesMan); } } public SecurityAdvisor addSiteUpdateSecurityAdvisor(){ // Cheating to become admin in order to modify authz groups SecurityAdvisor yesMan = new SecurityAdvisor() { public SecurityAdvice isAllowed(String userId, String function, String reference) { if("site.upd".equals(function)) return SecurityAdvice.ALLOWED; return SecurityAdvice.PASS; } }; securityService.pushAdvisor(yesMan); return yesMan; } public void popSecurityAdvisor(SecurityAdvisor advisor){ securityService.popAdvisor(advisor); } public String getTermField(){ return serverConfigurationService.getString(DelegatedAccessConstants.PROPERTIES_TERMFIELD, "term_eid"); } public boolean useCourseManagementApiForTerms(){ return serverConfigurationService.getBoolean(DelegatedAccessConstants.PROPERTIES_TERM_USE_CM_API, true); } public int showLatestXTerms(){ return serverConfigurationService.getInt(DelegatedAccessConstants.PROPERTIES_TERM_SHOW_LATEST_X_TERMS, -1); } public List<String[]> getTerms(){ if(terms == null){ terms = new ArrayList<String[]>(); if(!useCourseManagementApiForTerms()){ //user has set sakai.properties to override the coursemanagement API List<String> termsList = dao.getDistinctSiteTerms(getTermField()); //check for term order if exists: String[] termOrder = serverConfigurationService.getStrings("portal.term.order"); List<String> termOrderList = new ArrayList<String>(); if(termOrder != null && termOrder.length > 0){ Collections.addAll(termOrderList, termOrder); for(String term : termOrderList){ if(termsList.contains(term)){ terms.add(new String[]{term, term}); } } } //add the remaining (non ordered) termsho for(String term : termsList){ if(termOrderList == null || termOrderList.size() == 0 || !termOrderList.contains(term)) terms.add(new String[]{term, term}); } }else{ //use sakai's coursemanagement API to get the term options List<AcademicSession> academicSessions = cms.getAcademicSessions(); if(academicSessions != null){ Collections.sort(academicSessions, new Comparator<AcademicSession>() { @Override public int compare(AcademicSession o1, AcademicSession o2) { if(o1.getStartDate() == null){ return -1; }else if(o2.getStartDate() == null){ return 1; }else{ return o2.getStartDate().compareTo(o1.getStartDate()); } } }); for(AcademicSession session : academicSessions){ String termId = session.getEid(); if(!"term_eid".equals(getTermField())){ termId = session.getTitle(); } terms.add(new String[]{termId, session.getTitle()}); } } } //if there is a setting to only show the last X terms, int showLatestXTerms = showLatestXTerms(); if(showLatestXTerms != -1){ //make sure the showLastXTerms doesn't do an IndexOutOfBounds showLatestXTerms = showLatestXTerms < terms.size() ? showLatestXTerms : terms.size(); terms = terms.subList(0, showLatestXTerms); } } return terms; } public void sendEmail(String subject, String body){ String toAddress = serverConfigurationService.getString(DelegatedAccessConstants.PROPERTIES_EMAIL_ERRORS); String fromAddress = toAddress; if(toAddress != null && !"".equals(toAddress)){ emailService.send(fromAddress, toAddress, subject, body, null, null, null); } } public boolean getDisableUserTreeView(){ return serverConfigurationService.getBoolean(DelegatedAccessConstants.PROP_DISABLE_USER_TREE_VIEW, false); } public boolean getDisableShoppingTreeView(){ return serverConfigurationService.getBoolean(DelegatedAccessConstants.PROP_DISABLE_SHOPPING_TREE_VIEW, false); } public boolean isUserInstructor(String userId, String siteId){ Site site = getSiteById(siteId); return isUserInstructor(userId, site); } private boolean isUserInstructor(String userId, Site site){ if(site != null){ if(site.getMember(userId) != null){ if(securityService.unlock(userId, "site.upd", siteService.siteReference(site.getId()))){ return true; } } } return false; } public List<User> getInstructorsForSite(String siteId){ List<User> instructors = new ArrayList<User>(); Site site = getSiteById(siteId); if(site != null){ for(Member member : site.getMembers()){ if(isUserInstructor(member.getUserId(), site)){ try { instructors.add(userDirectoryService.getUser(member.getUserId())); } catch (UserNotDefinedException e) { log.error(e.getMessage(), e); } } } } return instructors; } public boolean isUserMember(String userId, String siteRef){ return authzGroupService.getUserRole(userId, siteRef) != null; } public Map<String,String> isUserMember(String userId, Collection<String> siteRefs){ return authzGroupService.getUserRoles(userId, siteRefs); } public boolean isShoppingPeriodInstructorEditable(){ return serverConfigurationService.getBoolean(DelegatedAccessConstants.PROPERTIES_SHOPPING_INSTRUCTOR_EDITABLE, false); } public boolean getSyncMyworkspaceTool(){ return serverConfigurationService.getBoolean(DelegatedAccessConstants.PROPERTIES_SYNC_MYWORKSPACE_TOOL, true); } public String[] getHideRolesForInstructorViewAccess(){ return serverConfigurationService.getStrings(DelegatedAccessConstants.PROPERTIES_HIDE_ROLES_FOR_VIEW_ACCESS); } public String[] getSubAdminOrderedRealmRoles(){ return serverConfigurationService.getStrings(DelegatedAccessConstants.PROPERTIES_SUBADMIN_REALM_ROLE_ORDER); } /** * DAC-40 Highlight Inactive Courses in site search * requires the job "InactiveCoursesJob" attached in the jira */ public boolean isActiveSiteFlagEnabled(){ return serverConfigurationService.getBoolean(DelegatedAccessConstants.PROPERTIES_ENABLE_ACTIVE_SITE_FLAG, false); } public void setSessionUserId(String userId){ sessionManager.getCurrentSession().setUserId(userId); } public boolean allowAccessAdminsSetBecomeUserPerm(){ return serverConfigurationService.getBoolean(DelegatedAccessConstants.PROPERTIES_ACCESS_ADMIN_ALLOW_SET_ALLOW_BECOME_USER, true); } }