/* * NOTE: This copyright does *not* cover user programs that use HQ * program services by normal system calls through the application * program interfaces provided as part of the Hyperic Plug-in Development * Kit or the Hyperic Client Development Kit - this is merely considered * normal use of the program, and does *not* fall under the heading of * "derived work". * * Copyright (C) [2004-2008], Hyperic, Inc. * This file is part of HQ. * * HQ is free software; you can redistribute it and/or modify * it under the terms version 2 of the GNU General Public License 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 * USA. */ package org.hyperic.hq.authz.server.session; import java.util.ArrayList; import java.util.Collection; import java.util.Collections; import javax.annotation.PostConstruct; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; import org.hyperic.hq.auth.server.session.UserAuditFactory; import org.hyperic.hq.auth.shared.SubjectNotFoundException; import org.hyperic.hq.authz.shared.AuthzConstants; import org.hyperic.hq.authz.shared.AuthzSubjectManager; import org.hyperic.hq.authz.shared.AuthzSubjectValue; import org.hyperic.hq.authz.shared.PermissionException; import org.hyperic.hq.authz.shared.PermissionManager; import org.hyperic.hq.common.ApplicationException; import org.hyperic.hq.common.NotFoundException; import org.hyperic.hq.common.server.session.Crispo; import org.hyperic.hq.common.shared.CrispoManager; import org.hyperic.util.config.ConfigResponse; import org.hyperic.util.pager.PageControl; import org.hyperic.util.pager.PageList; import org.hyperic.util.pager.Pager; import org.hyperic.util.pager.SortAttribute; import org.springframework.beans.BeansException; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.context.ApplicationContext; import org.springframework.context.ApplicationContextAware; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; /** * * */ @Service("authzSubjectManager") @Transactional public class AuthzSubjectManagerImpl implements AuthzSubjectManager, ApplicationContextAware { private final Log log = LogFactory.getLog(AuthzSubjectManagerImpl.class); private static final String SUBJECT_PAGER = PagerProcessor_subject.class.getName(); private Pager subjectPager; private AuthzSubjectDAO authzSubjectDAO; private ResourceTypeDAO resourceTypeDAO; private ResourceDAO resourceDAO; private CrispoManager crispoManager; private PermissionManager permissionManager; private UserAuditFactory userAuditFactory; private ApplicationContext applicationContext; @Autowired public AuthzSubjectManagerImpl(AuthzSubjectDAO authzSubjectDAO, ResourceTypeDAO resourceTypeDAO, ResourceDAO resourceDAO, CrispoManager crispoManager, PermissionManager permissionManager, UserAuditFactory userAuditFactory) { this.authzSubjectDAO = authzSubjectDAO; this.resourceTypeDAO = resourceTypeDAO; this.resourceDAO = resourceDAO; this.crispoManager = crispoManager; this.permissionManager = permissionManager; this.userAuditFactory = userAuditFactory; } @PostConstruct public void afterPropertiesSet() throws Exception { subjectPager = Pager.getPager(SUBJECT_PAGER); } /** * Find the subject that has the given name and authentication source. * @param name Name of the subject. * @param authDsn DSN of the authentication source. Authentication sources * are defined externally. * @return The value-object of the subject of the given name and * authenticating source. */ @Transactional(readOnly = true) public AuthzSubject findSubjectByAuth(String name, String authDsn) throws SubjectNotFoundException { AuthzSubject subject = authzSubjectDAO.findByAuth(name, authDsn); if (subject == null) { throw new SubjectNotFoundException("Can't find subject: name=" + name + ",authDsn=" + authDsn); } return subject; } /** * Create a subject. * @param whoami The current running user. * @return Value-object for the new Subject. * */ public AuthzSubject createSubject(AuthzSubject whoami, String name, boolean active, String dsn, String dept, String email, String first, String last, String phone, String sms, boolean html) throws PermissionException, ApplicationException { permissionManager.check(whoami.getId(), resourceTypeDAO.findTypeResourceType(), AuthzConstants.rootResourceId, AuthzConstants.subjectOpCreateSubject); AuthzSubject existing = authzSubjectDAO.findByName(name); if (existing != null) { throw new ApplicationException("A system user already exists with " + name); } AuthzSubject subjectPojo = authzSubjectDAO.create(whoami, name, active, dsn, dept, email, first, last, phone, sms, html); userAuditFactory.createAudit(whoami, subjectPojo); return subjectPojo; } /** * Update user settings for the target * * @param whoami The current running user. * @param target The subject to save. * * The rest of the parameters specify settings to update. If they are * null, then no change will be made to them. * */ public void updateSubject(AuthzSubject whoami, AuthzSubject target, Boolean active, String dsn, String dept, String email, String firstName, String lastName, String phone, String sms, Boolean useHtml) throws PermissionException { if (!whoami.getId().equals(target.getId())) { permissionManager.check(whoami.getId(), resourceTypeDAO.findTypeResourceType(), AuthzConstants.rootResourceId, AuthzConstants.subjectOpModifySubject); } if (active != null && target.getActive() != active.booleanValue()) { // Root user can not be disabled if (target.getId().equals(AuthzConstants.rootSubjectId)) { throw new PermissionException("Cannot change active status of " + "root user"); } target.setActive(active.booleanValue()); userAuditFactory.updateAudit(whoami, target, AuthzSubjectField.ACTIVE, target .getActive() + "", active + ""); } if (dsn != null && !dsn.equals(target.getAuthDsn())) { target.setAuthDsn(dsn); } if (dept != null && !dept.equals(target.getDepartment())) { target.setDepartment(dept); userAuditFactory.updateAudit(whoami, target, AuthzSubjectField.DEPT, target .getDepartment(), dept); } if (email != null && !email.equals(target.getEmailAddress())) { target.setEmailAddress(email); userAuditFactory.updateAudit(whoami, target, AuthzSubjectField.EMAIL, target .getEmailAddress(), email); } if (useHtml != null && target.getHtmlEmail() != useHtml.booleanValue()) { target.setHtmlEmail(useHtml.booleanValue()); userAuditFactory.updateAudit(whoami, target, AuthzSubjectField.HTML, target .getHtmlEmail() + "", useHtml + ""); } if (firstName != null && !firstName.equals(target.getFirstName())) { target.setFirstName(firstName); userAuditFactory.updateAudit(whoami, target, AuthzSubjectField.FIRSTNAME, target .getFirstName(), firstName); } if (lastName != null && !lastName.equals(target.getLastName())) { target.setLastName(lastName); userAuditFactory.updateAudit(whoami, target, AuthzSubjectField.LASTNAME, target .getLastName(), lastName); } if (phone != null && !phone.equals(target.getPhoneNumber())) { target.setPhoneNumber(phone); userAuditFactory.updateAudit(whoami, target, AuthzSubjectField.PHONE, target .getPhoneNumber(), phone); } if (sms != null && !sms.equals(target.getSMSAddress())) { target.setSMSAddress(sms); userAuditFactory.updateAudit(whoami, target, AuthzSubjectField.SMS, target .getSMSAddress(), sms); } } /** * Check if a subject can modify users * */ @Transactional(readOnly = true) public void checkModifyUsers(AuthzSubject caller) throws PermissionException { permissionManager.check(caller.getId(), resourceTypeDAO.findTypeResourceType(), AuthzConstants.rootResourceId, AuthzConstants.subjectOpModifySubject); } /** * Delete the specified subject. * * @param whoami The current running user. * @param subject The ID of the subject to delete. * */ public void removeSubject(AuthzSubject whoami, Integer subject) throws PermissionException { // no removing of the root user! if (subject.equals(AuthzConstants.rootSubjectId)) { throw new PermissionException("Root user can not be deleted"); } AuthzSubject toDelete = authzSubjectDAO.findById(subject); // XXX Should we do anything special for the "suicide" case? // Perhaps a _log message? if (!whoami.getId().equals(subject)) { permissionManager.check(whoami.getId(), resourceTypeDAO.findTypeResourceType().getId(), AuthzConstants.rootResourceId, AuthzConstants.perm_removeSubject); } // Reassign all resources to the root user before deleting resourceDAO.reassignResources(subject.intValue(), AuthzConstants.rootSubjectId.intValue()); applicationContext.publishEvent(new SubjectDeleteRequestedEvent(toDelete)); authzSubjectDAO.remove(toDelete); } /** * */ @Transactional(readOnly = true) public AuthzSubject findByAuth(String name, String authDsn) { return authzSubjectDAO.findByAuth(name, authDsn); } /** * */ @Transactional(readOnly = true) public AuthzSubject findSubjectById(AuthzSubject whoami, Integer id) throws PermissionException { // users can see their own entries without requiring special permission if (!whoami.getId().equals(id)) { permissionManager.check(whoami.getId(), resourceTypeDAO.findTypeResourceType().getId(), AuthzConstants.rootResourceId, AuthzConstants.perm_viewSubject); } return findSubjectById(id); } @Transactional(readOnly = true) public AuthzSubject findSubjectById(Integer id) { return authzSubjectDAO.findById(id); } @Transactional(readOnly = true) public String findSubjectName(Integer id) { return findSubjectById(id).getName(); } /** * */ @Transactional(readOnly = true) public AuthzSubject getSubjectById(Integer id) { return authzSubjectDAO.get(id); } /** * */ @Transactional(readOnly = true) public AuthzSubject findSubjectByName(AuthzSubject whoami, String name) throws PermissionException { return findSubjectByName(name); } /** * */ @Transactional(readOnly = true) public AuthzSubject findSubjectByName(String name) { return authzSubjectDAO.findByName(name); } /** * */ @Transactional(readOnly = true) public PageList<AuthzSubject> findMatchingName(String name, PageControl pc) { return authzSubjectDAO.findMatchingName(name, pc); } /** * List all subjects in the system * * @param excludes the IDs of subjects to exclude from result */ @Transactional(readOnly = true) public PageList<AuthzSubjectValue> getAllSubjects(AuthzSubject whoami, Collection<Integer> excludes, PageControl pc) throws NotFoundException, PermissionException { pc = PageControl.initDefaults(pc, SortAttribute.SUBJECT_NAME); // if a user does not have permission to view subjects, // all they can see is their own entry. AuthzSubject who = authzSubjectDAO.findById(whoami.getId()); Collection<AuthzSubject> subjects; try { permissionManager.check(whoami.getId(), resourceTypeDAO.findTypeResourceType(), AuthzConstants.rootResourceId, AuthzConstants.subjectOpViewSubject); if (!permissionManager.hasGuestRole()) { if (excludes == null) { excludes = new ArrayList<Integer>(1); } excludes.add(AuthzConstants.guestId); } } catch (PermissionException e) { PageList<AuthzSubjectValue> plist = new PageList<AuthzSubjectValue>(); // return a list with only the one entry. plist.add(who.getAuthzSubjectValue()); plist.setTotalSize(1); return plist; } switch (pc.getSortattribute()) { case SortAttribute.SUBJECT_NAME: if (who.isRoot()) subjects = authzSubjectDAO.findAllRoot_orderName(excludes, pc.isAscending()); else subjects = authzSubjectDAO.findAll_orderName(excludes, pc.isAscending()); break; case SortAttribute.FIRST_NAME: if (who.isRoot()) subjects = authzSubjectDAO.findAllRoot_orderFirstName(excludes, pc .isAscending()); else subjects = authzSubjectDAO.findAll_orderFirstName(excludes, pc.isAscending()); break; case SortAttribute.LAST_NAME: if (who.isRoot()) subjects = authzSubjectDAO .findAllRoot_orderLastName(excludes, pc.isAscending()); else subjects = authzSubjectDAO.findAll_orderLastName(excludes, pc.isAscending()); break; default: throw new NotFoundException("Unrecognized sort attribute: " + pc.getSortattribute()); } return subjectPager.seek(subjects, pc.getPagenum(), pc.getPagesize()); } /** * Get the subjects with the specified ids * * NOTE: This method returns an empty PageList if a null or empty array of * ids is received. * @param ids the subject ids * */ @Transactional(readOnly = true) public PageList<AuthzSubjectValue> getSubjectsById(AuthzSubject subject, Integer[] ids, PageControl pc) throws PermissionException { // PR7251 - Sometimes and for no good reason, different parts of the UI // call this method with an empty ids array. In this case, simply return // an empty page list. if (ids == null || ids.length == 0) { return new PageList<AuthzSubjectValue>(); } // find the requested subjects PageList<AuthzSubject> subjects = authzSubjectDAO.findById_orderName(ids, pc); // check permission unless the list includes only the id of // the subject being requested. This is ugly mostly because // we're using a list api to possibly look up a single Item if (subjects.size() > 0) { log.debug("Checking if Subject: " + subject.getName() + " can list subjects."); permissionManager.check(subject.getId(), resourceTypeDAO.findTypeResourceType(), AuthzConstants.rootResourceId, AuthzConstants.subjectOpViewSubject); } // Need to convert to value objects return new PageList<AuthzSubjectValue>(subjectPager.seek(subjects, PageControl.PAGE_ALL), subjects.getTotalSize()); } /** * Get the subjects with the specified ids * * NOTE: This method returns an empty list if a null or empty array of * ids is received. * @param ids the subject ids * */ @Transactional(readOnly = true) public Collection<AuthzSubject> getSubjectsById(AuthzSubject subject, Integer[] ids) throws PermissionException { if (ids == null || ids.length == 0) { return Collections.emptyList(); } // find the requested subjects Collection<AuthzSubject> subjects = authzSubjectDAO.findByIds(ids); // check permission unless the list includes only the id of // the subject being requested. This is ugly mostly because // we're using a list api to possibly look up a single Item if (subjects.size() > 0) { log.debug("Checking if Subject: " + subject.getName() + " can list subjects."); permissionManager.check(subject.getId(), resourceTypeDAO.findTypeResourceType(), AuthzConstants.rootResourceId, AuthzConstants.subjectOpViewSubject); } return subjects; } /** * Find the e-mail of the subject specified by id * @param id id of the subject. * @return The e-mail address of the subject * */ @Transactional(readOnly = true) public String getEmailById(Integer id) { AuthzSubject subject = authzSubjectDAO.findById(id); return subject.getEmailAddress(); } /** * Find the e-mail of the subject specified by name * @param userName Name of the subjects. * @return The e-mail address of the subject * */ @Transactional(readOnly = true) public String getEmailByName(String userName) { AuthzSubject subject = authzSubjectDAO.findByName(userName); return subject.getEmailAddress(); } /** * Get the Preferences for a specified user * */ @Transactional(readOnly = true) public ConfigResponse getUserPrefs(AuthzSubject who, Integer subjId) throws PermissionException { // users can always see their own prefs. if (!who.getId().equals(subjId)) { // check that the caller can see users permissionManager.check(who.getId(), resourceTypeDAO.findTypeResourceType(), AuthzConstants.rootResourceId, AuthzConstants.subjectOpViewSubject); } AuthzSubject targ = authzSubjectDAO.findById(subjId); Crispo c = targ.getPrefs(); if (c == null) return new ConfigResponse(); return c.toResponse(); } /** * Set the Preferences for a specified user * */ public void setUserPrefs(AuthzSubject who, Integer subjId, ConfigResponse prefs) throws PermissionException { // check to see if the user attempting the modification // is the same as the one being modified if (!(who.getId().intValue() == subjId.intValue())) { permissionManager.check(who.getId(), resourceTypeDAO.findTypeResourceType(), AuthzConstants.rootResourceId, AuthzConstants.subjectOpModifySubject); } AuthzSubject targ = authzSubjectDAO.findById(subjId); if (targ.getPrefs() != null) crispoManager.update(targ.getPrefs(), prefs); else { Crispo newPrefs = crispoManager.create(prefs); targ.setPrefs(newPrefs); } } public void setUserPrefs(Integer whoId, Integer subjectId, ConfigResponse prefs) throws PermissionException, SubjectNotFoundException { AuthzSubject who = getSubjectById(whoId); if(who == null) { throw new SubjectNotFoundException("Subject with id " + whoId + " not found"); } setUserPrefs(who, subjectId, prefs); } /** * */ @Transactional(readOnly = true) public AuthzSubject getOverlordPojo() { AuthzSubject overlord = authzSubjectDAO.findById(AuthzConstants.overlordId); //initialize name to pass Subject b/w method during non-tx testing overlord.getName(); return overlord; } public void setApplicationContext(ApplicationContext applicationContext) throws BeansException { this.applicationContext = applicationContext; } }