/* * Licensed to the Apache Software Foundation (ASF) under one * or more contributor license agreements. See the NOTICE file * distributed with this work for additional information * regarding copyright ownership. The ASF licenses this file * to you under the Apache 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.apache.org/licenses/LICENSE-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 privileges and * limitations under the License. */ package org.apache.ambari.server.controller.internal; import java.util.ArrayList; import java.util.Collections; import java.util.HashMap; import java.util.HashSet; import java.util.LinkedList; import java.util.List; import java.util.Map; import java.util.Set; import org.apache.ambari.server.AmbariException; import org.apache.ambari.server.DuplicateResourceException; import org.apache.ambari.server.controller.spi.NoSuchParentResourceException; import org.apache.ambari.server.controller.spi.NoSuchResourceException; import org.apache.ambari.server.controller.spi.Predicate; import org.apache.ambari.server.controller.spi.Request; import org.apache.ambari.server.controller.spi.RequestStatus; import org.apache.ambari.server.controller.spi.Resource; import org.apache.ambari.server.controller.spi.ResourceAlreadyExistsException; import org.apache.ambari.server.controller.spi.SystemException; import org.apache.ambari.server.controller.spi.UnsupportedPropertyException; import org.apache.ambari.server.orm.dao.GroupDAO; import org.apache.ambari.server.orm.dao.PermissionDAO; import org.apache.ambari.server.orm.dao.PrincipalDAO; import org.apache.ambari.server.orm.dao.PrivilegeDAO; import org.apache.ambari.server.orm.dao.ResourceDAO; import org.apache.ambari.server.orm.dao.UserDAO; import org.apache.ambari.server.orm.entities.GroupEntity; import org.apache.ambari.server.orm.entities.PermissionEntity; import org.apache.ambari.server.orm.entities.PrincipalEntity; import org.apache.ambari.server.orm.entities.PrincipalTypeEntity; import org.apache.ambari.server.orm.entities.PrivilegeEntity; import org.apache.ambari.server.orm.entities.ResourceEntity; import org.apache.ambari.server.orm.entities.UserEntity; import org.apache.commons.lang.StringUtils; /** * Abstract resource provider for privilege resources. */ public abstract class PrivilegeResourceProvider<T> extends AbstractAuthorizedResourceProvider { /** * Data access object used to obtain privilege entities. */ protected static PrivilegeDAO privilegeDAO; /** * Data access object used to obtain user entities. */ protected static UserDAO userDAO; /** * Data access object used to obtain group entities. */ protected static GroupDAO groupDAO; /** * Data access object used to obtain principal entities. */ protected static PrincipalDAO principalDAO; /** * Data access object used to obtain permission entities. */ protected static PermissionDAO permissionDAO; /** * Data access object used to obtain resource entities. */ protected static ResourceDAO resourceDAO; /** * Privilege property id constants. */ public static final String PRIVILEGE_ID_PROPERTY_ID = "PrivilegeInfo/privilege_id"; public static final String PERMISSION_NAME_PROPERTY_ID = "PrivilegeInfo/permission_name"; public static final String PERMISSION_LABEL_PROPERTY_ID = "PrivilegeInfo/permission_label"; public static final String PRINCIPAL_NAME_PROPERTY_ID = "PrivilegeInfo/principal_name"; public static final String PRINCIPAL_TYPE_PROPERTY_ID = "PrivilegeInfo/principal_type"; /** * The privilege resource type. */ private final Resource.Type resourceType; // ----- Constructors ------------------------------------------------------ /** * Construct a privilege resource provider. */ public PrivilegeResourceProvider(Set<String> propertyIds, Map<Resource.Type, String> keyPropertyIds, Resource.Type resourceType) { super(propertyIds, keyPropertyIds); this.resourceType = resourceType; } // ----- PrivilegeResourceProvider ---------------------------------------- /** * Static initialization. * * @param privDAO the privilege data access object * @param usrDAO the user data access object * @param grpDAO the group data access object * @param prinDAO the principal data access object * @param permDAO the permission data access object * @param resDAO the resource data access object */ public static void init(PrivilegeDAO privDAO, UserDAO usrDAO, GroupDAO grpDAO, PrincipalDAO prinDAO, PermissionDAO permDAO, ResourceDAO resDAO) { privilegeDAO = privDAO; userDAO = usrDAO; groupDAO = grpDAO; principalDAO = prinDAO; permissionDAO = permDAO; resourceDAO = resDAO; } /** * Get the entities for the owning resources from the given properties. * * @param properties the set of properties * * @return the entities * @throws AmbariException if resource entities were not found */ public abstract Map<Long, T> getResourceEntities(Map<String, Object> properties) throws AmbariException; /** * Get the id for the resource specified by predicate. * * @param predicate predicate * * @return the resource id */ public abstract Long getResourceEntityId(Predicate predicate); // ----- ResourceProvider -------------------------------------------------- @Override public RequestStatus createResourcesAuthorized(Request request) throws SystemException, UnsupportedPropertyException, ResourceAlreadyExistsException, NoSuchParentResourceException { for (Map<String, Object> properties : request.getProperties()) { createResources(getCreateCommand(properties)); } notifyCreate(resourceType, request); return getRequestStatus(null); } @Override public Set<Resource> getResourcesAuthorized(Request request, Predicate predicate) throws SystemException, UnsupportedPropertyException, NoSuchResourceException, NoSuchParentResourceException { Set<Resource> resources = new HashSet<>(); Set<String> requestedIds = getRequestPropertyIds(request, predicate); Set<Long> resourceIds = new HashSet<>(); Set<Map<String, Object>> propertyMaps = getPropertyMaps(predicate); if (propertyMaps.isEmpty()) { propertyMaps.add(Collections.<String, Object>emptyMap()); } for (Map<String, Object> properties : propertyMaps) { Map<Long, T> resourceEntities; try { resourceEntities = getResourceEntities(properties); } catch (AmbariException e) { throw new SystemException("Could not get resource list from request", e); } resourceIds.addAll(resourceEntities.keySet()); Set<PrivilegeEntity> entitySet = new HashSet<>(); List<PrincipalEntity> userPrincipals = new LinkedList<>(); List<PrincipalEntity> groupPrincipals = new LinkedList<>(); List<PrincipalEntity> rolePrincipals = new LinkedList<>(); List<PrivilegeEntity> entities = privilegeDAO.findAll(); for(PrivilegeEntity privilegeEntity : entities){ if (resourceIds.contains(privilegeEntity.getResource().getId())) { PrincipalEntity principal = privilegeEntity.getPrincipal(); String principalType = principal.getPrincipalType().getName(); entitySet.add(privilegeEntity); if(PrincipalTypeEntity.USER_PRINCIPAL_TYPE_NAME.equals(principalType)) { userPrincipals.add(principal); } else if(PrincipalTypeEntity.GROUP_PRINCIPAL_TYPE_NAME.equals(principalType)) { groupPrincipals.add(principal); } else if(PrincipalTypeEntity.ROLE_PRINCIPAL_TYPE_NAME.equals(principalType)) { rolePrincipals.add(principal); } } } Map<Long, UserEntity> userEntities = new HashMap<>(); if(!userPrincipals.isEmpty()) { List<UserEntity> userList = userDAO.findUsersByPrincipal(userPrincipals); for (UserEntity userEntity : userList) { userEntities.put(userEntity.getPrincipal().getId(), userEntity); } } Map<Long, GroupEntity> groupEntities = new HashMap<>(); if(!groupPrincipals.isEmpty()) { List<GroupEntity> groupList = groupDAO.findGroupsByPrincipal(groupPrincipals); for (GroupEntity groupEntity : groupList) { groupEntities.put(groupEntity.getPrincipal().getId(), groupEntity); } } Map<Long, PermissionEntity> roleEntities = new HashMap<>(); if (!rolePrincipals.isEmpty()){ List<PermissionEntity> roleList = permissionDAO.findPermissionsByPrincipal(rolePrincipals); for (PermissionEntity roleEntity : roleList) { roleEntities.put(roleEntity.getPrincipal().getId(), roleEntity); } } for(PrivilegeEntity privilegeEntity : entitySet){ Resource resource = toResource(privilegeEntity, userEntities, groupEntities, roleEntities, resourceEntities, requestedIds); if (resource != null && (predicate == null || predicate.evaluate(resource))) { resources.add(resource); } } } return resources; } @Override public RequestStatus updateResourcesAuthorized(Request request, Predicate predicate) throws SystemException, UnsupportedPropertyException, NoSuchResourceException, NoSuchParentResourceException { modifyResources(getUpdateCommand(request, predicate)); notifyUpdate(resourceType, request, predicate); return getRequestStatus(null); } @Override public RequestStatus deleteResourcesAuthorized(Request request, Predicate predicate) throws SystemException, UnsupportedPropertyException, NoSuchResourceException, NoSuchParentResourceException { modifyResources(getDeleteCommand(predicate)); notifyDelete(resourceType, predicate); return getRequestStatus(null); } // ----- AbstractResourceProvider ------------------------------------------ @Override protected Set<String> getPKPropertyIds() { return new HashSet<>(getKeyPropertyIds().values()); } // ----- helper methods ---------------------------------------------------- /** * Check to see if the given privilege entity's permission is allowable for the * resource type. * * @param entity the privilege entity * * @throws AmbariException if the the privilege permission is not allowable for the resource type */ protected boolean checkResourceTypes(PrivilegeEntity entity) throws AmbariException { Integer resourceType = entity.getResource().getResourceType().getId(); Integer permissionResourceType = entity.getPermission().getResourceType().getId(); return resourceType.equals(permissionResourceType); } /** * Convert the given privilege entity into a Resource. * * @param privilegeEntity the privilege entity to be converted * @param userEntities the map of user entities keyed by resource id * @param groupEntities the map of group entities keyed by resource id * @param roleEntities the map of role entities keyed by resource id * @param resourceEntities the map of resource entities keyed by resource id * @param requestedIds the requested property ids * * @return the resource */ protected Resource toResource(PrivilegeEntity privilegeEntity, Map<Long, UserEntity> userEntities, Map<Long, GroupEntity> groupEntities, Map<Long, PermissionEntity> roleEntities, Map<Long, T> resourceEntities, Set<String> requestedIds) { Resource resource = new ResourceImpl(resourceType); PrincipalEntity principal = privilegeEntity.getPrincipal(); String principalTypeName = null; String resourcePropertyName = null; if(principal != null) { PrincipalTypeEntity principalType = principal.getPrincipalType(); if (principalType != null) { Long principalId = principal.getId(); principalTypeName = principalType.getName(); if (StringUtils.equalsIgnoreCase(PrincipalTypeEntity.GROUP_PRINCIPAL_TYPE_NAME, principalTypeName)) { GroupEntity groupEntity = groupEntities.get(principalId); if (groupEntity != null) { resourcePropertyName = groupEntity.getGroupName(); } } else if (StringUtils.equalsIgnoreCase(PrincipalTypeEntity.ROLE_PRINCIPAL_TYPE_NAME, principalTypeName)) { PermissionEntity roleEntity = roleEntities.get(principalId); if (roleEntity != null) { resourcePropertyName = roleEntity.getPermissionName(); } } else if (StringUtils.equalsIgnoreCase(PrincipalTypeEntity.USER_PRINCIPAL_TYPE_NAME, principalTypeName)) { UserEntity userEntity = userEntities.get(principalId); if (userEntity != null) { resourcePropertyName = userEntity.getUserName(); } } } } setResourceProperty(resource, PRIVILEGE_ID_PROPERTY_ID, privilegeEntity.getId(), requestedIds); setResourceProperty(resource, PERMISSION_NAME_PROPERTY_ID, privilegeEntity.getPermission().getPermissionName(), requestedIds); setResourceProperty(resource, PERMISSION_LABEL_PROPERTY_ID, privilegeEntity.getPermission().getPermissionLabel(), requestedIds); setResourceProperty(resource, PRINCIPAL_NAME_PROPERTY_ID, resourcePropertyName, requestedIds); setResourceProperty(resource, PRINCIPAL_TYPE_PROPERTY_ID, principalTypeName, requestedIds); return resource; } /** * Convert the given map of properties to a privilege entity for the resource * identified by the given id. * * @param properties the property map * @param resourceId the resource id * * @return the new privilege entity */ protected PrivilegeEntity toEntity(Map<String, Object> properties, Long resourceId) throws AmbariException { PrivilegeEntity entity = new PrivilegeEntity(); String permissionName = (String) properties.get(PERMISSION_NAME_PROPERTY_ID); ResourceEntity resourceEntity = resourceDAO.findById(resourceId); PermissionEntity permission = getPermission(permissionName, resourceEntity); if (permission == null) { throw new AmbariException("Can't find a permission named " + permissionName + " for the resource."); } entity.setPermission(permission); entity.setResource(resourceEntity); String principalName = (String) properties.get(PRINCIPAL_NAME_PROPERTY_ID); String principalType = (String) properties.get(PRINCIPAL_TYPE_PROPERTY_ID); if (StringUtils.equalsIgnoreCase(PrincipalTypeEntity.GROUP_PRINCIPAL_TYPE_NAME, principalType)) { GroupEntity groupEntity = groupDAO.findGroupByName(principalName); if (groupEntity != null) { entity.setPrincipal(principalDAO.findById(groupEntity.getPrincipal().getId())); } } else if (StringUtils.equalsIgnoreCase(PrincipalTypeEntity.ROLE_PRINCIPAL_TYPE_NAME, principalType)) { PermissionEntity permissionEntity = permissionDAO.findByName(principalName); if (permissionEntity != null) { entity.setPrincipal(principalDAO.findById(permissionEntity.getPrincipal().getId())); } } else if (StringUtils.equalsIgnoreCase(PrincipalTypeEntity.USER_PRINCIPAL_TYPE_NAME, principalType)) { UserEntity userEntity = userDAO.findUserByName(principalName); if (userEntity != null) { entity.setPrincipal(principalDAO.findById(userEntity.getPrincipal().getId())); } } else { throw new AmbariException("Unknown principal type " + principalType); } if (entity.getPrincipal() == null) { throw new AmbariException("Could not find " + principalType + " named " + principalName); } return entity; } // Get a permission with the given permission name for the given resource. protected PermissionEntity getPermission(String permissionName, ResourceEntity resourceEntity) throws AmbariException { return permissionDAO.findPermissionByNameAndType(permissionName, resourceEntity.getResourceType()); } // Create a create command with the given properties map. private Command<Void> getCreateCommand(final Map<String, Object> properties) { return new Command<Void>() { @Override public Void invoke() throws AmbariException { // for a create there should only be one resource ... Set<Long> resourceIds = getResourceEntities(properties).keySet(); Long resourceId = resourceIds.iterator().next(); PrivilegeEntity entity = toEntity(properties, resourceId); if (entity.getPrincipal() == null) { throw new AmbariException("Can't find principal " + properties.get(PRINCIPAL_TYPE_PROPERTY_ID) + " " + properties.get(PRINCIPAL_NAME_PROPERTY_ID) + " for privilege."); } if (privilegeDAO.exists(entity)) { throw new DuplicateResourceException("The privilege already exists."); } if (!checkResourceTypes(entity)) { throw new AmbariException("Can't grant " + entity.getPermission().getResourceType().getName() + " permission on a " + entity.getResource().getResourceType().getName() + " resource."); } privilegeDAO.create(entity); entity.getPrincipal().getPrivileges().add(entity); principalDAO.merge(entity.getPrincipal()); return null; } }; } // Create a delete command with the given predicate. private Command<Void> getDeleteCommand(final Predicate predicate) { return new Command<Void>() { @Override public Void invoke() throws AmbariException { try { for (Map<String, Object> resource : getPropertyMaps(predicate)) { if (resource.get(PRIVILEGE_ID_PROPERTY_ID) == null) { throw new AmbariException("Privilege ID should be provided for this request"); } PrivilegeEntity entity = privilegeDAO.findById(Integer.valueOf(resource.get(PRIVILEGE_ID_PROPERTY_ID).toString())); if (entity != null) { if (!checkResourceTypes(entity)) { throw new AmbariException("Can't remove " + entity.getPermission().getResourceType().getName() + " permission from a " + entity.getResource().getResourceType().getName() + " resource."); } entity.getPrincipal().getPrivileges().remove(entity); principalDAO.merge(entity.getPrincipal()); privilegeDAO.remove(entity); } } } catch (Exception e) { throw new AmbariException("Caught exception deleting privilege.", e); } return null; } }; } private Command<Void> getUpdateCommand(final Request request, final Predicate predicate) { return new Command<Void>() { @Override public Void invoke() throws AmbariException { Long resource = null; final List<PrivilegeEntity> requiredEntities = new ArrayList<>(); for (Map<String, Object> properties: request.getProperties()) { Set<Long> resourceIds = getResourceEntities(properties).keySet(); Long resourceId = resourceIds.iterator().next(); if (resource != null && resourceId != resource) { throw new AmbariException("Can't update privileges of multiple resources in one request"); } resource = resourceId; PrivilegeEntity entity = toEntity(properties, resourceId); requiredEntities.add(entity); } if (resource == null) { // request body is empty, use predicate instead resource = getResourceEntityId(predicate); // if the predicate does not identify a single resource or the resource is not available for update if (resource == null) { return null; } } final List<PrivilegeEntity> currentPrivileges = privilegeDAO.findByResourceId(resource); for (PrivilegeEntity requiredPrivilege: requiredEntities) { boolean isInBothLists = false; for (PrivilegeEntity currentPrivilege: currentPrivileges) { if (requiredPrivilege.getPermission().getPermissionName().equals(currentPrivilege.getPermission().getPermissionName()) && requiredPrivilege.getPrincipal().getId().equals(currentPrivilege.getPrincipal().getId())) { isInBothLists = true; break; } } if (!isInBothLists) { if (!checkResourceTypes(requiredPrivilege)) { throw new AmbariException("Can't grant " + requiredPrivilege.getPermission().getResourceType().getName() + " permission on a " + requiredPrivilege.getResource().getResourceType().getName() + " resource."); } privilegeDAO.create(requiredPrivilege); requiredPrivilege.getPrincipal().getPrivileges().add(requiredPrivilege); principalDAO.merge(requiredPrivilege.getPrincipal()); } } for (PrivilegeEntity currentPrivilege: currentPrivileges) { boolean isInBothLists = false; for (PrivilegeEntity requiredPrivilege: requiredEntities) { if (requiredPrivilege.getPermission().getPermissionName().equals(currentPrivilege.getPermission().getPermissionName()) && requiredPrivilege.getPrincipal().getId().equals(currentPrivilege.getPrincipal().getId())) { isInBothLists = true; break; } } if (!isInBothLists) { if (!checkResourceTypes(currentPrivilege)) { throw new AmbariException("Can't remove " + currentPrivilege.getPermission().getResourceType().getName() + " permission from a " + currentPrivilege.getResource().getResourceType().getName() + " resource."); } currentPrivilege.getPrincipal().getPrivileges().remove(currentPrivilege); principalDAO.merge(currentPrivilege.getPrincipal()); privilegeDAO.remove(currentPrivilege); } } return null; } }; } }