/* * 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 permissions and * limitations under the License. */ package org.apache.ambari.server.controller.internal; import java.util.Collection; import java.util.Collections; import java.util.HashMap; import java.util.HashSet; import java.util.Map; import java.util.Set; import org.apache.ambari.server.StaticallyInject; import org.apache.ambari.server.controller.AmbariManagementController; import org.apache.ambari.server.controller.predicate.EqualsPredicate; import org.apache.ambari.server.controller.spi.ClusterController; 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.Resource; import org.apache.ambari.server.controller.spi.Resource.Type; import org.apache.ambari.server.controller.spi.ResourceProvider; import org.apache.ambari.server.controller.spi.SystemException; import org.apache.ambari.server.controller.spi.UnsupportedPropertyException; import org.apache.ambari.server.controller.utilities.ClusterControllerHelper; import org.apache.ambari.server.controller.utilities.PropertyHelper; import org.apache.ambari.server.orm.dao.PermissionDAO; import org.apache.ambari.server.orm.dao.ResourceTypeDAO; import org.apache.ambari.server.orm.entities.PermissionEntity; import org.apache.ambari.server.orm.entities.ResourceTypeEntity; import org.apache.ambari.server.orm.entities.RoleAuthorizationEntity; import org.apache.ambari.server.security.authorization.AuthorizationException; import org.apache.ambari.server.security.authorization.AuthorizationHelper; import org.apache.ambari.server.security.authorization.ResourceType; import org.apache.ambari.server.security.authorization.RoleAuthorization; import com.google.inject.Inject; /** * A write-only resource provider for securely stored credentials */ @StaticallyInject public class UserAuthorizationResourceProvider extends ReadOnlyResourceProvider { // ----- Property ID constants --------------------------------------------- public static final String AUTHORIZATION_ID_PROPERTY_ID = PropertyHelper.getPropertyId("AuthorizationInfo", "authorization_id"); public static final String USERNAME_PROPERTY_ID = PropertyHelper.getPropertyId("AuthorizationInfo", "user_name"); public static final String AUTHORIZATION_NAME_PROPERTY_ID = PropertyHelper.getPropertyId("AuthorizationInfo", "authorization_name"); public static final String AUTHORIZATION_RESOURCE_TYPE_PROPERTY_ID = PropertyHelper.getPropertyId("AuthorizationInfo", "resource_type"); public static final String AUTHORIZATION_CLUSTER_NAME_PROPERTY_ID = PropertyHelper.getPropertyId("AuthorizationInfo", "cluster_name"); public static final String AUTHORIZATION_VIEW_NAME_PROPERTY_ID = PropertyHelper.getPropertyId("AuthorizationInfo", "view_name"); public static final String AUTHORIZATION_VIEW_VERSION_PROPERTY_ID = PropertyHelper.getPropertyId("AuthorizationInfo", "view_version"); public static final String AUTHORIZATION_VIEW_INSTANCE_NAME_PROPERTY_ID = PropertyHelper.getPropertyId("AuthorizationInfo", "view_instance_name"); private static final Set<String> PK_PROPERTY_IDS; private static final Set<String> PROPERTY_IDS; private static final Map<Type, String> KEY_PROPERTY_IDS; static { Set<String> set; set = new HashSet<>(); set.add(AUTHORIZATION_ID_PROPERTY_ID); set.add(USERNAME_PROPERTY_ID); set.add(AUTHORIZATION_RESOURCE_TYPE_PROPERTY_ID); PK_PROPERTY_IDS = Collections.unmodifiableSet(set); set = new HashSet<>(); set.add(AUTHORIZATION_ID_PROPERTY_ID); set.add(USERNAME_PROPERTY_ID); set.add(AUTHORIZATION_NAME_PROPERTY_ID); set.add(AUTHORIZATION_RESOURCE_TYPE_PROPERTY_ID); set.add(AUTHORIZATION_CLUSTER_NAME_PROPERTY_ID); set.add(AUTHORIZATION_VIEW_NAME_PROPERTY_ID); set.add(AUTHORIZATION_VIEW_VERSION_PROPERTY_ID); set.add(AUTHORIZATION_VIEW_INSTANCE_NAME_PROPERTY_ID); PROPERTY_IDS = Collections.unmodifiableSet(set); HashMap<Type, String> map = new HashMap<>(); map.put(Type.User, USERNAME_PROPERTY_ID); map.put(Type.UserAuthorization, AUTHORIZATION_ID_PROPERTY_ID); KEY_PROPERTY_IDS = Collections.unmodifiableMap(map); } /** * Data access object used to obtain permission entities. */ @Inject private static PermissionDAO permissionDAO; /** * Data access object used to obtain resource type entities. */ @Inject private static ResourceTypeDAO resourceTypeDAO; /** * The ClusterController user to get access to other resource providers */ private final ClusterController clusterController; /** * For testing purposes */ public static void init(PermissionDAO permissionDAO, ResourceTypeDAO resourceTypeDAO) { UserAuthorizationResourceProvider.permissionDAO = permissionDAO; UserAuthorizationResourceProvider.resourceTypeDAO = resourceTypeDAO; } /** * Create a new resource provider. */ public UserAuthorizationResourceProvider(AmbariManagementController managementController) { super(PROPERTY_IDS, KEY_PROPERTY_IDS, managementController); clusterController = ClusterControllerHelper.getClusterController(); } @Override public Set<Resource> getResources(Request request, Predicate predicate) throws SystemException, UnsupportedPropertyException, NoSuchResourceException, NoSuchParentResourceException { Set<String> requestedIds = getRequestPropertyIds(request, predicate); Set<Resource> resources = new HashSet<>(); // Use the UserPrivilegeProvider to get the set of privileges the user has. This set of privileges // is used to generate a composite set of authorizations the user has been granted. ResourceProvider userPrivilegeProvider = clusterController.ensureResourceProvider(Type.UserPrivilege); boolean isUserAdministrator = AuthorizationHelper.isAuthorized(ResourceType.AMBARI, null, RoleAuthorization.AMBARI_MANAGE_USERS); for (Map<String, Object> propertyMap : getPropertyMaps(predicate)) { String username = (String) propertyMap.get(USERNAME_PROPERTY_ID); // Ensure that the authenticated user has authorization to get this information if (!isUserAdministrator && !AuthorizationHelper.getAuthenticatedName().equalsIgnoreCase(username)) { throw new AuthorizationException(); } Request internalRequest = createUserPrivilegeRequest(); Predicate internalPredicate = createUserPrivilegePredicate(username); Set<Resource> internalResources = userPrivilegeProvider.getResources(internalRequest, internalPredicate); if (internalResources != null) { for (Resource internalResource : internalResources) { String permissionName = (String) internalResource.getPropertyValue(UserPrivilegeResourceProvider.PRIVILEGE_PERMISSION_NAME_PROPERTY_ID); String resourceType = (String) internalResource.getPropertyValue(UserPrivilegeResourceProvider.PRIVILEGE_TYPE_PROPERTY_ID); Collection<RoleAuthorizationEntity> authorizationEntities; ResourceTypeEntity resourceTypeEntity = resourceTypeDAO.findByName(resourceType); if (resourceTypeEntity != null) { PermissionEntity permissionEntity = permissionDAO.findPermissionByNameAndType(permissionName, resourceTypeEntity); if (permissionEntity == null) { authorizationEntities = null; } else { authorizationEntities = permissionEntity.getAuthorizations(); } if (authorizationEntities != null) { // The details about the resource that the user has been granted access to are // different depending on the resource type specified in the privilege entity if ("VIEW".equals(resourceType)) { addViewResources(resources, username, resourceType, internalResource, authorizationEntities, requestedIds); } else { addClusterResources(resources, username, resourceType, internalResource, authorizationEntities, requestedIds); } } } } } } return resources; } @Override protected Set<String> getPKPropertyIds() { return PK_PROPERTY_IDS; } /** * Create a predicate to use to query for the user's set of privileges * * @param username the username of the relevant user * @return a predicate */ private Predicate createUserPrivilegePredicate(String username) { return new EqualsPredicate<>(UserPrivilegeResourceProvider.PRIVILEGE_USER_NAME_PROPERTY_ID, username); } /** * Create a request to use to query for the user's set of privileges * * @return a request */ private Request createUserPrivilegeRequest() { Set<String> propertyIds = new HashSet<>(); propertyIds.add(UserPrivilegeResourceProvider.PRIVILEGE_PRIVILEGE_ID_PROPERTY_ID); propertyIds.add(UserPrivilegeResourceProvider.PRIVILEGE_PERMISSION_NAME_PROPERTY_ID); propertyIds.add(UserPrivilegeResourceProvider.PRIVILEGE_TYPE_PROPERTY_ID); propertyIds.add(UserPrivilegeResourceProvider.PRIVILEGE_CLUSTER_NAME_PROPERTY_ID); propertyIds.add(UserPrivilegeResourceProvider.PRIVILEGE_VIEW_NAME_PROPERTY_ID); propertyIds.add(UserPrivilegeResourceProvider.PRIVILEGE_VIEW_VERSION_PROPERTY_ID); propertyIds.add(UserPrivilegeResourceProvider.PRIVILEGE_INSTANCE_NAME_PROPERTY_ID); return new RequestImpl(propertyIds, null, null, null); } /** * Creates and adds resources to the results where each resource properly identities the cluster * to which the authorization data applies. * <p/> * Generates an AuthorizationInfo block containing the following fields: * <ul> * <li>authorization_id</li> * <li>authorization_name</li> * <li>cluster_name</li> * <li>resource_type</li> * <li>user_name</li> * </ul> * * @param resources the set of resources to amend * @param username the username * @param resourceType the resource type (typically "CLUSTER" or "AMBARI") * @param privilegeResource the privilege resource used for retrieving cluster-specific details * @param authorizationEntities relevant AuthorizationEntity values for this authorization * @param requestedIds the properties to include in the resulting resource instance */ private void addClusterResources(Set<Resource> resources, String username, String resourceType, Resource privilegeResource, Collection<RoleAuthorizationEntity> authorizationEntities, Set<String> requestedIds) { for (RoleAuthorizationEntity entity : authorizationEntities) { Resource resource = new ResourceImpl(Type.UserAuthorization); setResourceProperty(resource, AUTHORIZATION_ID_PROPERTY_ID, entity.getAuthorizationId(), requestedIds); setResourceProperty(resource, USERNAME_PROPERTY_ID, username, requestedIds); setResourceProperty(resource, AUTHORIZATION_NAME_PROPERTY_ID, entity.getAuthorizationName(), requestedIds); setResourceProperty(resource, AUTHORIZATION_RESOURCE_TYPE_PROPERTY_ID, resourceType, requestedIds); setResourceProperty(resource, AUTHORIZATION_CLUSTER_NAME_PROPERTY_ID, privilegeResource.getPropertyValue(UserPrivilegeResourceProvider.PRIVILEGE_CLUSTER_NAME_PROPERTY_ID), requestedIds); resources.add(resource); } } /** * Creates and adds resources to the results where each resource properly identities the view * to which the authorization data applies. * <p/> * Generates an AuthorizationInfo block containing the following fields: * <ul> * <li>authorization_id</li> * <li>authorization_name</li> * <li>resource_type</li> * <li>view_name</li> * <li>view_version</li> * <li>view_instance_name</li> * <li>user_name</li> * </ul> * * @param resources the set of resources to amend * @param username the username * @param resourceType the resource type (typically "VIEW") * @param privilegeResource the privilege resource used for retrieving view-specific details * @param authorizationEntities relevant AuthorizationEntity values for this authorization * @param requestedIds the properties to include in the resulting resource instance */ private void addViewResources(Set<Resource> resources, String username, String resourceType, Resource privilegeResource, Collection<RoleAuthorizationEntity> authorizationEntities, Set<String> requestedIds) { for (RoleAuthorizationEntity entity : authorizationEntities) { Resource resource = new ResourceImpl(Type.UserAuthorization); setResourceProperty(resource, AUTHORIZATION_ID_PROPERTY_ID, entity.getAuthorizationId(), requestedIds); setResourceProperty(resource, USERNAME_PROPERTY_ID, username, requestedIds); setResourceProperty(resource, AUTHORIZATION_NAME_PROPERTY_ID, entity.getAuthorizationName(), requestedIds); setResourceProperty(resource, AUTHORIZATION_RESOURCE_TYPE_PROPERTY_ID, resourceType, requestedIds); setResourceProperty(resource, AUTHORIZATION_VIEW_NAME_PROPERTY_ID, privilegeResource.getPropertyValue(UserPrivilegeResourceProvider.PRIVILEGE_VIEW_NAME_PROPERTY_ID), requestedIds); setResourceProperty(resource, AUTHORIZATION_VIEW_VERSION_PROPERTY_ID, privilegeResource.getPropertyValue(UserPrivilegeResourceProvider.PRIVILEGE_VIEW_VERSION_PROPERTY_ID), requestedIds); setResourceProperty(resource, AUTHORIZATION_VIEW_INSTANCE_NAME_PROPERTY_ID, privilegeResource.getPropertyValue(UserPrivilegeResourceProvider.PRIVILEGE_INSTANCE_NAME_PROPERTY_ID), requestedIds); resources.add(resource); } } }