/*
* 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-2009], 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.shared;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.Comparator;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import java.util.TreeSet;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.hibernate.Query;
import org.hyperic.hq.appdef.shared.AppdefEntityID;
import org.hyperic.hq.appdef.shared.AppdefUtil;
import org.hyperic.hq.authz.server.session.AuthzSubject;
import org.hyperic.hq.authz.server.session.Operation;
import org.hyperic.hq.authz.server.session.OperationDAO;
import org.hyperic.hq.authz.server.session.Resource;
import org.hyperic.hq.authz.server.session.ResourceDAO;
import org.hyperic.hq.authz.server.session.ResourceGroup;
import org.hyperic.hq.authz.server.session.ResourceGroupDAO;
import org.hyperic.hq.authz.server.session.ResourceType;
import org.hyperic.hq.authz.server.session.Role;
import org.hyperic.hq.authz.server.session.RoleDAO;
import org.hyperic.hq.common.ApplicationException;
import org.hyperic.hq.common.NotFoundException;
import org.hyperic.hq.common.SystemException;
import org.hyperic.hq.context.Bootstrap;
import org.hyperic.hq.events.shared.HierarchicalAlertingManager;
import org.hyperic.hq.events.shared.MaintenanceEventManager;
import org.hyperic.util.IntegerTransformer;
import org.hyperic.util.StringUtil;
import org.hyperic.util.jdbc.DBUtil;
import org.hyperic.util.pager.PageControl;
import org.hyperic.util.pager.Pager;
import org.hyperic.util.pager.SortAttribute;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
@Component("permissionManager")
public class PermissionManagerImpl extends PermissionManager {
private static final Log _log = LogFactory.getLog(PermissionManagerImpl.class.getName());
private final String _falseToken;
private DBUtil dbUtil;
private OperationDAO operationDAO;
private static final String VIEWABLE_SELECT = "SELECT instance_id, EAM_RESOURCE.sort_name, EAM_RESOURCE.id, "
+ "EAM_RESOURCE.resource_type_id "
+ "FROM EAM_RESOURCE ";
private static final String VIEWABLE_CLAUSE = " EAM_RESOURCE.fsystem = DB_FALSE_TOKEN AND "
+ "EAM_RESOURCE.resource_type_id = "
+ "(SELECT rt.id FROM EAM_RESOURCE_TYPE rt WHERE rt.name = ?) ";
private static final String VIEWABLE_BYNAME_SQL = " AND (lower(EAM_RESOURCE.name) like lower('%$$resName$$%') OR "
+ " EAM_RESOURCE.instance_id in (SELECT appdef_id FROM EAM_CPROP, "
+ " EAM_CPROP_KEY WHERE keyid = EAM_CPROP_KEY.id AND "
+ " appdef_type = ? AND lower(propvalue) like lower('%$$resName$$%'))) ";
private static final String ALL_RESOURCE_SQL = "SELECT res.instance_id FROM EAM_RESOURCE res, EAM_OPERATION o "
+ "WHERE o.resource_type_id = res.resource_type_id and o.id = ?";
private static final String VIEWABLE_SEARCH = "WHERE EAM_RESOURCE.fsystem = DB_FALSE_TOKEN AND "
+ "RESOURCE_TYPE_ID IN (3, 301, 303, 305, 308) AND "
+ "(SORT_NAME LIKE UPPER(?) OR "
+ "PROTO_ID IN (SELECT ID FROM EAM_RESOURCE "
+ "WHERE PROTO_ID = 0 AND SORT_NAME LIKE UPPER(?))) ";
private Connection getConnection() throws SQLException {
return dbUtil.getConnection();
}
@Autowired
public PermissionManagerImpl(DBUtil dbUtil, OperationDAO operationDAO) {
Connection conn = null;
this.dbUtil = dbUtil;
this.operationDAO = operationDAO;
try {
conn = getConnection();
_falseToken = DBUtil.getBooleanValue(false, conn);
} catch (Exception e) {
throw new SystemException("Unable to initialize " + "PermissionManager:" + e, e);
} finally {
DBUtil.closeConnection(PermissionManagerImpl.class, conn);
}
}
public void check(Integer subject, ResourceType type, Integer instanceId, String operation)
throws PermissionException {
}
public void check(Integer subjectId, Integer typeId, Integer instanceId, Integer operationId)
throws PermissionException {
}
public void check(Integer subjectId, String resType, Integer instanceId, String operation)
throws PermissionException {
}
public void check(Integer subjectId, Integer typeId, Integer operationId)
throws PermissionException{
}
public boolean hasAdminPermission(Integer who) {
return true;
}
public Collection<Integer> findOperationScopeBySubject(AuthzSubject subj, String opName,
String resType)
throws NotFoundException,
PermissionException {
if (_log.isDebugEnabled()) {
_log.debug("Checking Scope for Operation: " + opName + " subject: " + subj);
}
ResourceType resTypeBean = getResourceTypeDAO().findByName(resType);
if (resTypeBean != null) {
Operation op = getOperationDAO().findByTypeAndName(resTypeBean, opName);
if (op != null) {
return findOperationScopeBySubject(subj, op.getId());
}
}
return new ArrayList<Integer>();
}
public Collection<Integer> findOperationScopeBySubject(AuthzSubject subj, Integer opId)
throws NotFoundException, PermissionException {
if (_log.isDebugEnabled()) {
_log.debug("Checking Scope for Operation: " + opId + " subject: " + subj);
}
List<Integer> scope = findScopeBySQL(subj, opId);
if (_log.isDebugEnabled()) {
_log.debug("Scope check returned a size of : " + scope.size() + " items");
}
return scope;
}
public Resource[] findOperationScopeBySubjectBatch(AuthzSubject whoami, ResourceValue[] resArr,
String[] opArr) throws ApplicationException {
if (resArr == null) {
throw new IllegalArgumentException("At least one resource required");
}
Set resLocArr = toPojos(resArr);
return (Resource[]) resLocArr.toArray(new Resource[resLocArr.size()]);
}
protected RoleDAO getRoleDAO() {
return Bootstrap.getBean(RoleDAO.class);
}
protected ResourceGroupDAO getResourceGroupDAO() {
return Bootstrap.getBean(ResourceGroupDAO.class);
}
private Resource lookupResource(ResourceValue resource) {
if (resource.getId() == null) {
ResourceType type = resource.getResourceType();
return getResourceDAO().findByInstanceId(type, resource.getInstanceId());
}
return getResourceDAO().findById(resource.getId());
}
private Set toPojos(Object[] vals) {
Set ret = new HashSet();
if (vals == null || vals.length == 0) {
return ret;
}
RoleDAO roleDao = null;
ResourceGroupDAO resGrpDao = null;
for (int i = 0; i < vals.length; i++) {
if (vals[i] instanceof Operation) {
ret.add(vals[i]);
} else if (vals[i] instanceof ResourceValue) {
ret.add(lookupResource((ResourceValue) vals[i]));
} else if (vals[i] instanceof RoleValue) {
if (roleDao == null) {
roleDao = getRoleDAO();
}
ret.add(roleDao.findById(((RoleValue) vals[i]).getId()));
} else if (vals[i] instanceof ResourceGroupValue) {
if (resGrpDao == null) {
resGrpDao = getResourceGroupDAO();
}
ret.add(resGrpDao.findById(((ResourceGroupValue) vals[i]).getId()));
} else {
_log.error("Invalid type.");
}
}
return ret;
}
public List<Integer> findViewableResources(AuthzSubject subj, String searchFor, PageControl pc) {
List<Integer> viewableInstances = new ArrayList<Integer>();
Connection conn = null;
PreparedStatement stmt = null;
ResultSet rs = null;
try {
conn = getConnection();
String sql = VIEWABLE_SELECT + VIEWABLE_SEARCH;
// TODO: change sort by
sql += "ORDER BY EAM_RESOURCE.resource_type_id, " + "EAM_RESOURCE.sort_name ";
if (!pc.isAscending()) {
sql = sql + "DESC";
}
sql = StringUtil.replace(sql, "DB_FALSE_TOKEN", _falseToken);
if (searchFor == null) {
searchFor = "%";
} else {
// Support wildcards
searchFor = '%' + searchFor.replace('*', '%') + '%';
}
stmt = conn.prepareStatement(sql);
int i = 1;
stmt.setString(i++, searchFor);
stmt.setString(i++, searchFor);
if (_log.isDebugEnabled())
_log.debug("Viewable search for (" + searchFor + ") SQL: " + sql);
rs = stmt.executeQuery();
for (i = 1; rs.next(); i++) {
viewableInstances.add(new Integer(rs.getInt(3)));
}
return viewableInstances;
} catch (SQLException e) {
_log.error("Error search by SQL", e);
throw new SystemException("SQL Error search: " + e.getMessage());
} finally {
DBUtil.closeJDBCObjects(PermissionManagerImpl.class, conn, stmt, rs);
}
}
private List<Integer> findScopeBySQL(AuthzSubject subj, Integer opId) throws NotFoundException,
PermissionException {
Pager defaultPager = Pager.getDefaultPager();
Connection conn = null;
PreparedStatement stmt = null;
ResultSet rs = null;
List<Integer> instanceIds = null;
try {
conn = getConnection();
// Always return all resources
stmt = conn.prepareStatement(ALL_RESOURCE_SQL);
stmt.setInt(1, opId.intValue());
rs = stmt.executeQuery();
// now build the list
instanceIds = new ArrayList<Integer>();
for (int i = 1; rs.next(); i++) {
instanceIds.add(new Integer(rs.getInt(1)));
}
return instanceIds;
} catch (SQLException e) {
_log.error("Error getting scope by SQL", e);
throw new NotFoundException("Error getting scope: " + e.getMessage());
} finally {
DBUtil.closeJDBCObjects(PermissionManagerImpl.class, conn, stmt, rs);
}
}
public List getAllOperations(AuthzSubject subject, PageControl pc) throws PermissionException {
Role rootRole = getRoleDAO().findById(AuthzConstants.rootRoleId);
Set ops = new HashSet();
ops.addAll(rootRole.getOperations());
pc = PageControl.initDefaults(pc, SortAttribute.OPERATION_NAME);
Pager operationPager;
try {
operationPager = Pager.getPager(OPERATION_PAGER);
} catch (Exception e) {
return null;
}
return operationPager.seek(ops, pc.getPagenum(), pc.getPagesize());
}
public Collection<Resource> getGroupResources(Integer subjectId, Integer groupId,
Boolean fsystem) {
return getResourceDAO().findInGroup_orderName(groupId, fsystem);
}
public Collection<Resource> findServiceResources(AuthzSubject subj, Boolean fsystem) {
return getResourceDAO().findSvcRes_orderName(fsystem);
}
public RolePermNativeSQL getRolePermissionNativeSQL(String resourceVar, String eventLogVar, String subjectParam,
String opListViewResourcesParam,
String opListManageAlertsParam) {
return new RolePermNativeSQL() {
public String getSQL() {
return "";
}
public Query bindParams(Query q, AuthzSubject subject, List opsViewResources, List opsManageAlerts) {
return q;
}
};
}
public String getAlertsHQL(boolean inEscalation, boolean notFixed, Integer groupId,
Integer resourceId, Integer alertDefId, boolean count) {
// Join with Resource for sorting
return "select " +
(count ? "count(a)" : "a") +
" from " +
(inEscalation ? "EscalationState es, " : "") +
"Alert a " +
"join a.alertDefinition d " +
"join d.resource r " +
"where r.resourceType is not null and " +
(groupId == null ? "" : "exists (select rg from r.groupBag rg " +
"where rg.group.id = " + groupId + ") and ") +
(resourceId == null ? "" : "r.id = " + resourceId + " and ") +
"a.ctime between :begin and :end and " + (notFixed ? " a.fixed = false and " : "") +
(alertDefId == null ? "" : "d.id = " + alertDefId + " and ") +
"d.priority >= :priority " +
(inEscalation ? "and a.id = es.alertId and " + "es.alertDefinitionId = d.id " : "");
}
public String getAlertDefsHQL() {
return "select d from AlertDefinition d " + "join d.resource r "
+ "where r.resourceType is not null and d.priority >= :priority";
}
public String getGroupAlertsHQL(boolean inEscalation, boolean notFixed, Integer groupId,
Integer galertDefId) {
return "select a from " + (inEscalation ? "EscalationState es, " : "") + "GalertLog a " +
"join a.alertDef d " + "where " +
(groupId != null ? " g.id = " + groupId + " and " : "") +
"a.timestamp between :begin and :end " + (notFixed ? " and a.fixed = false " : "") +
(galertDefId == null ? "" : "and d.id = " + galertDefId + " ") +
"and d.severityEnum >= :priority " +
(inEscalation ? "and a.id = es.alertId and " + "es.alertDefinitionId = d.id " : "");
}
public String getGroupAlertDefsHQL() {
return "select d from GalertDef d " + "join d.group g " + "join d.escalation e "
+ "where d.severityEnum >= :priority ";
}
public boolean hasGuestRole() {
return false;
}
public EdgePermCheck makePermCheckSql(String subjectParam, String resVar, String resParam,
String distanceParam, String opsParam,
boolean includeDescendants) {
final Integer cId = AuthzConstants.RELATION_CONTAINMENT_ID;
final String oper = (includeDescendants) ? ">=" : "=";
final String sql = new StringBuilder().append(" JOIN EAM_RESOURCE_EDGE edge")
.append(" ON ").append(resVar).append(".id = edge.TO_ID").append(" AND ")
.append(resVar).append(".id = edge.FROM_ID").append(" WHERE edge.distance ").append(
oper).append(" :").append(distanceParam).append(" AND edge.rel_id = ").append(cId)
.append(" AND ").append(resVar).append(".id = :").append(resParam).append(" ")
.toString();
return new EdgePermCheck(sql, subjectParam, resVar, resParam, distanceParam, opsParam) {
public Query addQueryParameters(Query q, AuthzSubject subject, Resource r,
int distance, List ops) {
return q.setInteger(getDistanceParam(), distance).setInteger(getResourceParam(),
r.getId().intValue());
}
};
}
public EdgePermCheck makePermCheckHql(String subjectParam, String resourceVar,
String resourceParam, String distanceParam,
String opsParam, boolean includeDescendants) {
final Integer cId = AuthzConstants.RELATION_CONTAINMENT_ID;
final String oper = (includeDescendants) ? ">=" : "=";
final String sql = new StringBuilder().append("join ").append(resourceVar).append(
".toEdges _e ").append("join _e.from _fromResource ").append("where ").append(
" _fromResource = :").append(resourceParam).append(" AND _e.distance ").append(oper)
.append(" :").append(distanceParam).append(" AND _e.relation.id = ").append(cId)
.append(' ').toString();
return new EdgePermCheck(sql, subjectParam, resourceVar, resourceParam, distanceParam,
opsParam) {
public Query addQueryParameters(Query q, AuthzSubject subject, Resource r,
int distance, List ops) {
return q.setInteger(getDistanceParam(), distance).setParameter(getResourceParam(),
r);
}
};
}
public String getOperableGroupsHQL(AuthzSubject subject, String alias, String oper) {
return "";
}
public String getSQLWhere(Integer subjectId) {
return "";
}
public MaintenanceEventManager getMaintenanceEventManager() {
return (MaintenanceEventManager) Bootstrap.getBean("MaintenanceEventManager");
}
public HierarchicalAlertingManager getHierarchicalAlertingManager() {
return (HierarchicalAlertingManager) Bootstrap.getBean("HierarchicalAlertingManager");
}
@Override
public Set<Integer> findViewablePSSResources(AuthzSubject subj) {
final Collection<ResourceType> types = new ArrayList<ResourceType>();
final ResourceManager resourceManager = Bootstrap.getBean(ResourceManager.class);
types.add(resourceManager.getResourceTypeById(AuthzConstants.authzPlatform));
types.add(resourceManager.getResourceTypeById(AuthzConstants.authzServer));
types.add(resourceManager.getResourceTypeById(AuthzConstants.authzService));
return findViewableResources(subj, types);
}
public List<AppdefEntityID> findViewableInstances(AuthzSubject subj,
Collection<ResourceType> resourceTypes) {
if (resourceTypes.isEmpty()) {
return Collections.emptyList();
}
final ResourceDAO resourceDAO = getResourceDAO();
final Collection<Resource> resources = (subj.getId().equals(1)) ?
resourceDAO.findAll() : resourceDAO.findByOwner(subj, PageControl.SORT_UNSORTED);
final List<AppdefEntityID> rtn = new ArrayList<AppdefEntityID>(resources.size());
final Set<Integer> typeIds = new HashSet<Integer>();
for (final ResourceType type : resourceTypes) {
typeIds.add(type.getId());
}
for (final Resource r : resources) {
if (r == null || r.isInAsyncDeleteState() || r.isSystem()) {
continue;
}
if (typeIds.contains(r.getResourceType().getId())) {
rtn.add(AppdefUtil.newAppdefEntityId(r));
}
}
return rtn;
}
public Set<Integer> findViewableResources(AuthzSubject subj, Collection<ResourceType> resourceTypes) {
return findViewableResources(subj, resourceTypes, new IntegerTransformer<Integer>() {
public Integer transform(Integer id) {
return id;
}
});
}
public <T> Set<T> findViewableResources(AuthzSubject subj, Collection<ResourceType> resourceTypes,
IntegerTransformer<T> transformer) {
return findViewableResources(subj, resourceTypes, PageControl.SORT_UNSORTED, transformer);
}
public <T> Set<T> findViewableResources(AuthzSubject subj, Collection<ResourceType> resourceTypes,
int sortName, IntegerTransformer<T> transformer) {
return findViewableResources(subj, resourceTypes, sortName, transformer, null);
}
@Override
public <T> Set<T> findViewableResources(AuthzSubject subj, Collection<ResourceType> resourceTypes,
int sortName, IntegerTransformer<T> transformer,
Comparator<T> comparator) {
if (resourceTypes.isEmpty()) {
return Collections.emptySet();
}
final ResourceDAO resourceDAO = getResourceDAO();
final Collection<Resource> resources = (subj.getId().equals(1)) ?
resourceDAO.findAllOrderByName() : resourceDAO.findByOwner(subj, sortName);
final Set<Integer> typeIds = new HashSet<Integer>();
final Set<T> rtn = (comparator != null) ? new TreeSet<T>(comparator) : new HashSet<T>();
for (final ResourceType type : resourceTypes) {
typeIds.add(type.getId());
}
for (final Resource r : resources) {
if (r == null || r.isInAsyncDeleteState() || r.isSystem()) {
continue;
}
final Integer id = r.getId();
final int typeId = r.getResourceType().getId();
if (typeIds.contains(typeId)) {
T val = transformer.transform(id);
if (val != null) {
rtn.add(val);
}
}
}
return rtn;
}
@Override
public <T> Set<T> findViewableResources(AuthzSubject subj, Collection<Role> roles,
Collection<ResourceType> resourceTypes, IntegerTransformer<T> transformer) {
Set<T> resourcesViewableByOwner = findViewableResources(subj, resourceTypes, PageControl.SORT_UNSORTED, transformer);
return resourcesViewableByOwner;
}
public TypeCounts findViewableInstanceCounts(AuthzSubject subj, Collection<ResourceType> types) {
final TypeCounts rtn = new TypeCounts();
if (types.isEmpty()) {
return rtn;
}
final ResourceDAO resourceDAO = getResourceDAO();
final Collection<Resource> resources = (subj.getId().equals(1)) ?
resourceDAO.findAll() : resourceDAO.findByOwner(subj, PageControl.SORT_UNSORTED);
final Set<Integer> typeIds = new HashSet<Integer>();
for (final ResourceType type : types) {
typeIds.add(type.getId());
}
ResourceGroupManager resourceGroupManager = Bootstrap.getBean(ResourceGroupManager.class);
for (final Resource r : resources) {
if (r == null || r.isInAsyncDeleteState() || r.isSystem() || !typeIds.contains(r.getResourceType().getId())) {
continue;
}
final int protoType = r.getPrototype().getId();
final AppdefEntityID aeid = AppdefUtil.newAppdefEntityId(r);
int appdefType = -1;
if (r.getResourceType().getId().equals(AuthzConstants.authzGroup)) {
ResourceGroup group = resourceGroupManager.getResourceGroupById(r.getInstanceId());
if (group == null) {
continue;
}
appdefType = group.getGroupType();
} else {
appdefType = aeid.getType();
}
rtn.incrementAppdefTypeCount(appdefType);
rtn.incrementProtoTypeCount(appdefType, protoType);
}
return rtn;
}
@Override
public <T> Set<T> findResourcesByOperationIds(AuthzSubject subj, Collection<Integer> operationIds,
IntegerTransformer<T> transformer) {
final List<ResourceType> resourceTypes = new ArrayList<ResourceType>();
for (final Integer opId : operationIds) {
final Operation op = operationDAO.findById(opId);
resourceTypes.add(op.getResourceType());
}
return findViewableResources(subj, resourceTypes, transformer);
}
}