/* * 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.bizapp.server.session; import java.util.ArrayList; import java.util.Collection; import java.util.LinkedHashMap; import java.util.List; import java.util.Map; import javax.security.auth.login.LoginException; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; import org.hyperic.hq.appdef.shared.AppdefEntityID; import org.hyperic.hq.appdef.shared.AppdefEntityNotFoundException; import org.hyperic.hq.appdef.shared.AppdefUtil; import org.hyperic.hq.appdef.shared.UpdateException; import org.hyperic.hq.auth.shared.AuthManager; import org.hyperic.hq.auth.shared.SessionException; import org.hyperic.hq.auth.shared.SessionManager; import org.hyperic.hq.auth.shared.SessionNotFoundException; import org.hyperic.hq.auth.shared.SessionTimeoutException; import org.hyperic.hq.authz.server.session.AuthzSubject; import org.hyperic.hq.authz.server.session.Operation; import org.hyperic.hq.authz.server.session.Resource; import org.hyperic.hq.authz.server.session.ResourceGroup; import org.hyperic.hq.authz.server.session.ResourceType; import org.hyperic.hq.authz.server.session.Role; import org.hyperic.hq.authz.server.session.UserPreferencesUpdatedEvent; import org.hyperic.hq.authz.server.session.events.subject.SubjectDeletedZevent; 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.authz.shared.ResourceGroupManager; import org.hyperic.hq.authz.shared.ResourceGroupValue; import org.hyperic.hq.authz.shared.ResourceManager; import org.hyperic.hq.bizapp.shared.AppdefBoss; import org.hyperic.hq.bizapp.shared.AuthBoss; import org.hyperic.hq.bizapp.shared.AuthzBoss; import org.hyperic.hq.common.ApplicationException; import org.hyperic.hq.common.NotFoundException; import org.hyperic.hq.common.SystemException; import org.hyperic.hq.zevents.ZeventEnqueuer; import org.hyperic.util.ConfigPropertyException; import org.hyperic.util.config.ConfigResponse; import org.hyperic.util.pager.PageControl; import org.hyperic.util.pager.PageList; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; /** * The BizApp's interface to the Authz Subsystem * */ @Service @Transactional public class AuthzBossImpl implements AuthzBoss { private SessionManager sessionManager; protected Log log = LogFactory.getLog(AuthzBossImpl.class.getName()); protected boolean debug = log.isDebugEnabled(); private AppdefBoss appdefBoss; private AuthManager authManager; private AuthBoss authBoss; private AuthzSubjectManager authzSubjectManager; private ResourceGroupManager resourceGroupManager; private ResourceManager resourceManager; private PermissionManager permissionManager; private ZeventEnqueuer zEventEnqueuer; @Autowired public AuthzBossImpl(SessionManager sessionManager, AppdefBoss appdefBoss, AuthBoss authBoss, AuthManager authManager, AuthzSubjectManager authzSubjectManager, ResourceGroupManager resourceGroupManager, ResourceManager resourceManager, PermissionManager permissionManager, ZeventEnqueuer zeventEnqueuer) { this.sessionManager = sessionManager; this.appdefBoss = appdefBoss; this.authManager = authManager; this.authBoss = authBoss; this.authzSubjectManager = authzSubjectManager; this.resourceGroupManager = resourceGroupManager; this.resourceManager = resourceManager; this.permissionManager = permissionManager; this.zEventEnqueuer = zeventEnqueuer; } /** * Check if the current logged in user can administer CAM * @return true - if user has adminsterCAM op false otherwise * */ @Transactional(readOnly=true) public boolean hasAdminPermission(int sessionId) throws SessionTimeoutException, SessionNotFoundException { AuthzSubject subject = sessionManager.getSubject(sessionId); return permissionManager.hasAdminPermission(subject.getId()); } /** * Return a sorted, paged <code>List</code> of * <code>ResourceTypeValue</code> objects representing every resource type * in the system that the user is allowed to view. * * */ @Transactional(readOnly=true) public List<ResourceType> getAllResourceTypes(Integer sessionId, PageControl pc) throws PermissionException, SessionTimeoutException, SessionNotFoundException { AuthzSubject subject = sessionManager.getSubject(sessionId); return resourceManager.getAllResourceTypes(subject, pc); } /** * Return the full <code>List</code> of <code>ResourceTypeValue</code> * objects representing every resource type in the system that the user is * allowed to view. * * */ @Transactional(readOnly=true) public List<ResourceType> getAllResourceTypes(Integer sessionId) throws PermissionException, SessionTimeoutException, SessionNotFoundException { return getAllResourceTypes(sessionId, null); } /** * Return a sorted, paged <code>List</code> of <code>OperationValue</code> * objects representing every resource type in the system that the user is * allowed to view. * * */ @Transactional(readOnly=true) public List<Operation> getAllOperations(Integer sessionId, PageControl pc) throws PermissionException, SessionTimeoutException, SessionNotFoundException { AuthzSubject subject = sessionManager.getSubject(sessionId); return permissionManager.getAllOperations(subject, pc); } /** * Return the full <code>List</code> of <code>OperationValue</code> objects * representing every resource type in the system that the user is allowed * to view. * * */ @Transactional(readOnly=true) public List<Operation> getAllOperations(Integer sessionId) throws PermissionException, SessionTimeoutException, SessionNotFoundException { return getAllOperations(sessionId, null); } /** * Return a sorted, paged <code>List</code> of * <code>AuthzSubjectValue</code> objects representing every resource type * in the system that the user is allowed to view. * * */ @Transactional(readOnly=true) public PageList<AuthzSubjectValue> getAllSubjects(Integer sessionId, Collection<Integer> excludes, PageControl pc) throws SessionTimeoutException, SessionNotFoundException, PermissionException, NotFoundException { AuthzSubject subject = sessionManager.getSubject(sessionId); return authzSubjectManager.getAllSubjects(subject, excludes, pc); } /** * Return a sorted, paged <code>List</code> of * <code>AuthzSubjectValue</code> objects corresponding to the specified id * values. * * */ @Transactional(readOnly=true) public PageList<AuthzSubjectValue> getSubjectsById(Integer sessionId, Integer[] ids, PageControl pc) throws PermissionException, SessionTimeoutException, SessionNotFoundException { AuthzSubject subject = sessionManager.getSubject(sessionId); return authzSubjectManager.getSubjectsById(subject, ids, pc); } /** * Return a sorted, paged <code>List</code> of * <code>AuthzSubjectValue</code> objects matching name as substring * * */ @Transactional(readOnly=true) public PageList<AuthzSubject> getSubjectsByName(Integer sessionId, String name, PageControl pc) throws PermissionException, SessionTimeoutException, SessionNotFoundException { sessionManager.getSubject(sessionId); return authzSubjectManager.findMatchingName(name, pc); } /** * Return a sorted, paged <code>List</code> of * <code>ResourceGroupValue</code> objects representing every resource type * in the system that the user is allowed to view. * * */ @Transactional(readOnly=true) public List<ResourceGroupValue> getAllResourceGroups(Integer sessionId, PageControl pc) throws PermissionException, SessionTimeoutException, SessionNotFoundException { AuthzSubject subject = sessionManager.getSubject(sessionId); return resourceGroupManager.getAllResourceGroups(subject, pc); } /** * Return a sorted, paged <code>List</code> of * <code>ResourceGroupValue</code> objects corresponding to the specified id * values. * * */ @Transactional(readOnly=true) public PageList<ResourceGroupValue> getResourceGroupsById(Integer sessionId, Integer[] ids, PageControl pc) throws PermissionException, SessionTimeoutException, SessionNotFoundException { AuthzSubject subject = sessionManager.getSubject(sessionId); return resourceGroupManager.getResourceGroupsById(subject, ids, pc); } /** * */ @Transactional(readOnly=true) public Map<AppdefEntityID, Resource> findResourcesByIds(Integer sessionId, AppdefEntityID[] entities) throws SessionNotFoundException, SessionTimeoutException { // get the user sessionManager.getSubject(sessionId); Map<AppdefEntityID, Resource> appdefMap = new LinkedHashMap<AppdefEntityID, Resource>(); // cheaper to find the resource first for (int i = 0; i < entities.length; i++) { Resource res = resourceManager.findResource(entities[i]); if (res != null && !res.isInAsyncDeleteState()) { try { appdefMap.put(AppdefUtil.newAppdefEntityId(res), res); } catch (IllegalArgumentException e) { // Not a valid appdef resource, continue } } } return appdefMap; } /** * Remove the user identified by the given ids from the subject as well as * principal tables. * * */ public void removeSubject(Integer sessionId, Integer[] ids) throws PermissionException, SessionTimeoutException, SessionNotFoundException, ApplicationException { // check for timeout AuthzSubject whoami = sessionManager.getSubject(sessionId); try { for (int i = 0; i < ids.length; i++) { AuthzSubject aSubject = findSubjectById(sessionId, ids[i]); /* * Note: This has not been finalized. At present, however, the * consensus is that a user should be able to be deleted if they * are logged in. Therefore, this fix may not be needed ... * BUG-4169 - DSE if (isLoggedIn(username)) { throw new * Exception ("User is logged in"); } */ // Verify that the user is not trying to delete themself. if (whoami.getName().equals(aSubject.getName())) { throw new PermissionException("Users are not permitted to remove themselves."); } final Collection<Role> roles = new ArrayList<Role>(aSubject.getRoles()); final Collection<ResourceGroup> ownedGroups = resourceGroupManager.getResourceGroupsByOwnerId(aSubject); // reassign ownership of all things authz resetResourceOwnership(sessionId, aSubject); // reassign ownership of all things appdef appdefBoss.resetResourceOwnership(sessionId.intValue(), aSubject); // delete in auth authManager.deleteUser(whoami, aSubject.getName()); // remove from authz authzSubjectManager.removeSubject(whoami, ids[i]); zEventEnqueuer.enqueueEventAfterCommit(new SubjectDeletedZevent(aSubject, roles, ownedGroups)); } } catch (UpdateException e) { throw new ApplicationException("Unable to reset ownership of owned resources: " + e.getMessage()); } catch (AppdefEntityNotFoundException e) { throw new ApplicationException("Unable to reset ownership of owned resources: " + e.getMessage()); } } /** * Update all the authz resources owned by this user to be owned by the root * user. This is done to prevent resources from being orphaned in the UI due * to its display restrictions. This method should only get called before a * user is about to be deleted * @param subject- the user about to be removed * */ private void resetResourceOwnership(Integer sessionId, AuthzSubject currentOwner) throws UpdateException, PermissionException { // first look up the resources by owner Collection<Resource> resources = resourceManager.findResourceByOwner(currentOwner); for (Resource aRes : resources) { String resType = aRes.getResourceType().getName(); if (resType.equals(AuthzConstants.roleResourceTypeName)|| resType.equals(AuthzConstants.subjectResourceTypeName)) { resourceManager.setResourceOwner(authzSubjectManager.getOverlordPojo(), aRes, authzSubjectManager .getOverlordPojo()); } } } /** * Update a subject * * */ public void updateSubject(Integer sessionId, AuthzSubject target, Boolean active, String dsn, String dept, String email, String first, String last, String phone, String sms, Boolean useHtml) throws PermissionException, SessionException { AuthzSubject whoami = sessionManager.getSubject(sessionId); authzSubjectManager.updateSubject(whoami, target, active, dsn, dept, email, first, last, phone, sms, useHtml); } /** * Create the user identified by the given ids from the subject as well as * principal tables. * * */ public AuthzSubject createSubject(Integer sessionId, String name, boolean active, String dsn, String dept, String email, String first, String last, String phone, String sms, boolean useHtml) throws PermissionException, SessionException, ApplicationException { // check for timeout AuthzSubject whoami = sessionManager.getSubject(sessionId); return authzSubjectManager.createSubject(whoami, name, active, dsn, dept, email, first, last, phone, sms, useHtml); } /** * */ @Transactional(readOnly=true) public AuthzSubject getCurrentSubject(int sessionid) throws SessionException { return sessionManager.getSubject(sessionid); } /** * */ @Transactional(readOnly=true) public AuthzSubject getCurrentSubject(String name) throws SessionException, ApplicationException { int sessionId = authBoss.getUnauthSessionId(name); return getCurrentSubject(sessionId); } /** * Return the <code>AuthzSubject</code> object identified by the given * subject id. * @throws SessionTimeoutException * @throws SessionNotFoundException * @throws PermissionException * * */ @Transactional(readOnly=true) public AuthzSubject findSubjectById(Integer sessionId, Integer subjectId) throws SessionNotFoundException, SessionTimeoutException, PermissionException { // check for timeout AuthzSubject subj = sessionManager.getSubject(sessionId); return authzSubjectManager.findSubjectById(subj, subjectId); } /** * Return the <code>AuthzSubject</code> object identified by the given * username. * * */ @Transactional(readOnly=true) public AuthzSubject findSubjectByName(Integer sessionId, String subjectName) throws SessionTimeoutException, SessionNotFoundException, PermissionException { // check for timeout AuthzSubject subj = sessionManager.getSubject(sessionId); return authzSubjectManager.findSubjectByName(subj, subjectName); } /** * Return the <code>AuthzSubject</code> object identified by the given * username. This method should only be used in cases where displaying the * user does not require an Authz check. An example of this is when the * owner and last modifier need to be displayed, and the user viewing the * resource does not have permissions to view other users. See bug #5452 for * more information * */ @Transactional(readOnly=true) public AuthzSubject findSubjectByNameNoAuthz(Integer sessionId, String subjectName) throws SessionTimeoutException, SessionNotFoundException, PermissionException { // check for timeout sessionManager.authenticate(sessionId.intValue()); return authzSubjectManager.findSubjectByName(subjectName); } /** * Return a ConfigResponse matching the UserPreferences * @throws ApplicationException * @throws ConfigPropertyException * @throws LoginException * */ @Transactional(readOnly=true) public ConfigResponse getUserPrefs(String username) throws SessionNotFoundException, ApplicationException, ConfigPropertyException { int sessionId = authBoss.getUnauthSessionId(username); AuthzSubject subject = sessionManager.getSubject(sessionId); return getUserPrefs(new Integer(sessionId), subject.getId()); } /** * Return a ConfigResponse matching the UserPreferences * */ @Transactional(readOnly=true) public ConfigResponse getUserPrefs(Integer sessionId, Integer subjectId) { try { AuthzSubject who = sessionManager.getSubject(sessionId); return authzSubjectManager.getUserPrefs(who, subjectId); } catch (Exception e) { throw new SystemException(e); } } @Transactional(readOnly=true) public void setUserPrefs(Integer sessionId, Integer subjectId, ConfigResponse prefs) throws ApplicationException, SessionTimeoutException, SessionNotFoundException { if (log.isDebugEnabled()) { log.debug("setting preferences for sessionid=" + sessionId + ", subjId=" + subjectId); } AuthzSubject who = sessionManager.getSubject(sessionId); zEventEnqueuer.enqueueEventAfterCommit(new UserPreferencesUpdatedEvent(who.getId(),subjectId,prefs)); } /** * Get the email of a user by name * */ @Transactional(readOnly=true) public String getEmailByName(Integer sessionId, String userName) throws SessionTimeoutException, SessionNotFoundException { sessionManager.authenticate(sessionId.intValue()); return authzSubjectManager.getEmailByName(userName); } /** * Get the email of a user by id * */ @Transactional(readOnly=true) public String getEmailById(Integer sessionId, Integer userId) throws SessionTimeoutException, SessionNotFoundException { sessionManager.authenticate(sessionId.intValue()); return authzSubjectManager.getEmailById(userId); } }