/* * 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.Collections; import java.util.HashSet; import java.util.Map; import java.util.Set; 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.PropertyProvider; 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.ResourceProvider; import org.apache.ambari.server.controller.spi.SystemException; import org.apache.ambari.server.controller.spi.UnsupportedPropertyException; 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 org.springframework.security.core.Authentication; /** * AbstractAuthorizedResourceProvider helps to provide an authorization layer for a resource provider. * <p/> * Resource providers that need to perform authorization checks should extend ths abstract class and * then override the <code>*ResourcesAuthorized</code> methods and set the <code>required*Authorizations</code> * properties. For more sophisticated authorization checks, the <code>isAuthorizedTo*Resources</code> * methods may be overwritten. * <p/> * Additionally, the {@link AuthorizationHelper#isAuthorized(ResourceType, Long, Set)} or * {@link AuthorizationHelper#verifyAuthorization(ResourceType, Long, Set)} methods may be called * within the logic of the resource provider implementation to provide checks on particular resources. * * @see AuthorizationHelper */ public abstract class AbstractAuthorizedResourceProvider extends AbstractResourceProvider { /** * The set of authorizations for which one is needed to the grant access to <b>create</b> resources * or a particular resource. */ private Set<RoleAuthorization> requiredCreateAuthorizations = Collections.emptySet(); /** * The set of authorizations for which one is needed to the grant access to <b>get</b> resources * or a particular resource. */ private Set<RoleAuthorization> requiredGetAuthorizations = Collections.emptySet(); /** * The set of authorizations for which one is needed to the grant access to <b>update</b> resources * or a particular resource. */ private Set<RoleAuthorization> requiredUpdateAuthorizations = Collections.emptySet(); /** * The set of authorizations for which one is needed to the grant access to <b>delete</b> resources * or a particular resource. */ private Set<RoleAuthorization> requiredDeleteAuthorizations = Collections.emptySet(); /** * Constructor * * @param propertyIds the property ids * @param keyPropertyIds the key property ids */ protected AbstractAuthorizedResourceProvider(Set<String> propertyIds, Map<Resource.Type, String> keyPropertyIds) { super(propertyIds, keyPropertyIds); } /** * Gets the authorizations for which one is needed to the grant access to <b>create</b> resources * or a particular resource. * <p/> * A null or empty set indicates no authorization check needs to be performed. * * @return a set of authorizations */ public Set<RoleAuthorization> getRequiredCreateAuthorizations() { return requiredCreateAuthorizations; } /** * Sets the authorizations for which one is needed to the grant access to <b>create</b> resources * or a particular resource. * <p/> * A null or empty set indicates no authorization check needs to be performed. * * @param requiredCreateAuthorizations a set of authorizations */ public void setRequiredCreateAuthorizations(Set<RoleAuthorization> requiredCreateAuthorizations) { this.requiredCreateAuthorizations = createUnmodifiableSet(requiredCreateAuthorizations); } /** * Gets the authorizations for which one is needed to the grant access to <b>get</b> resources * or a particular resource. * <p/> * A null or empty set indicates no authorization check needs to be performed. * * @return a set of authorizations */ public Set<RoleAuthorization> getRequiredGetAuthorizations() { return requiredGetAuthorizations; } /** * Sets the authorizations for which one is needed to the grant access to <b>get</b> resources * or a particular resource. * <p/> * A null or empty set indicates no authorization check needs to be performed. * * @param requiredGetAuthorizations a set of authorizations */ public void setRequiredGetAuthorizations(Set<RoleAuthorization> requiredGetAuthorizations) { this.requiredGetAuthorizations = createUnmodifiableSet(requiredGetAuthorizations); } /** * Gets the authorizations for which one is needed to the grant access to <b>update</b> resources * or a particular resource. * <p/> * A null or empty set indicates no authorization check needs to be performed. * * @return a set of authorizations */ public Set<RoleAuthorization> getRequiredUpdateAuthorizations() { return requiredUpdateAuthorizations; } /** * Sets the authorizations for which one is needed to the grant access to <b>update</b> resources * or a particular resource. * <p/> * A null or empty set indicates no authorization check needs to be performed. * * @param requiredUpdateAuthorizations a set of authorizations */ public void setRequiredUpdateAuthorizations(Set<RoleAuthorization> requiredUpdateAuthorizations) { this.requiredUpdateAuthorizations = createUnmodifiableSet(requiredUpdateAuthorizations); } /** * Gets the authorizations for which one is needed to the grant access to <b>delete</b> resources * or a particular resource. * <p/> * A null or empty set indicates no authorization check needs to be performed. * * @return a set of authorizations */ public Set<RoleAuthorization> getRequiredDeleteAuthorizations() { return requiredDeleteAuthorizations; } /** * Sets the authorizations for which one is needed to the grant access to <b>delete</b> resources * or a particular resource. * <p/> * A null or empty set indicates no authorization check needs to be performed. * * @param requiredDeleteAuthorizations a set of authorizations */ public void setRequiredDeleteAuthorizations(Set<RoleAuthorization> requiredDeleteAuthorizations) { this.requiredDeleteAuthorizations = createUnmodifiableSet(requiredDeleteAuthorizations); } // ----- ResourceProvider -------------------------------------------------- /** * Create the resources defined by the properties in the given request object. * <p/> * This implementation attempts to authorize the authenticated user before performing the requested * operation. If authorization fails, an AuthorizationException will be thrown. * <p/> * This method may be overwritten by implementing classes to avoid performing authorization checks * to create resources. * * @param request the request object which defines the set of properties * for the resources to be created * @return the request status * @throws SystemException an internal system exception occurred * @throws UnsupportedPropertyException the request contains unsupported property ids * @throws ResourceAlreadyExistsException attempted to create a resource which already exists * @throws NoSuchParentResourceException a parent resource of the resource to create doesn't exist * @throws AuthorizationException if the authenticated user is not authorized to perform this operation */ @Override public RequestStatus createResources(Request request) throws SystemException, UnsupportedPropertyException, ResourceAlreadyExistsException, NoSuchParentResourceException { Authentication authentication = AuthorizationHelper.getAuthentication(); if (authentication == null || !authentication.isAuthenticated()) { throw new AuthorizationException("Authentication data is not available, authorization to perform the requested operation is not granted"); } else if (!isAuthorizedToCreateResources(authentication, request)) { throw new AuthorizationException("The authenticated user does not have the appropriate authorizations to create the requested resource(s)"); } return createResourcesAuthorized(request); } /** * Get a set of {@link Resource resources} based on the given request and predicate * information. * </p> * Note that it is not required for this resource provider to completely filter * the set of resources based on the given predicate. It may not be possible * since some of the properties involved may be provided by another * {@link PropertyProvider provider}. This partial filtering is allowed because * the predicate will always be applied by the calling cluster controller. The * predicate is made available at this level so that some pre-filtering can be done * as an optimization. * </p> * A simple implementation of a resource provider may choose to just return all of * the resources of a given type and allow the calling cluster controller to filter * based on the predicate. * <p/> * This implementation attempts to authorize the authenticated user before performing the requested * operation. If authorization fails, an AuthorizationException will be thrown. * <p/> * This method may be overwritten by implementing classes to avoid performing authorization checks * to get resources. * * @param request the request object which defines the desired set of properties * @param predicate the predicate object which can be used to filter which * resources are returned * @return a set of resources based on the given request and predicate information * @throws SystemException an internal system exception occurred * @throws UnsupportedPropertyException the request contains unsupported property ids * @throws NoSuchResourceException the requested resource instance doesn't exist * @throws NoSuchParentResourceException a parent resource of the requested resource doesn't exist * @throws AuthorizationException if the authenticated user is not authorized to perform this operation */ @Override public Set<Resource> getResources(Request request, Predicate predicate) throws SystemException, UnsupportedPropertyException, NoSuchResourceException, NoSuchParentResourceException { Authentication authentication = AuthorizationHelper.getAuthentication(); if (authentication == null || !authentication.isAuthenticated()) { throw new AuthorizationException("Authentication data is not available, authorization to perform the requested operation is not granted"); } else if (!isAuthorizedToGetResources(authentication, request, predicate)) { throw new AuthorizationException("The authenticated user does not have the appropriate authorizations to get the requested resource(s)"); } return getResourcesAuthorized(request, predicate); } /** * Update the resources selected by the given predicate with the properties * from the given request object. * <p/> * This implementation attempts to authorize the authenticated user before performing the requested * operation. If authorization fails, an AuthorizationException will be thrown. * <p/> * This method may be overwritten by implementing classes to avoid performing authorization checks * to update resources. * * @param request the request object which defines the set of properties * for the resources to be updated * @param predicate the predicate object which can be used to filter which * resources are updated * @return the request status * @throws SystemException an internal system exception occurred * @throws UnsupportedPropertyException the request contains unsupported property ids * @throws NoSuchResourceException the resource instance to be updated doesn't exist * @throws NoSuchParentResourceException a parent resource of the resource doesn't exist * @throws AuthorizationException if the authenticated user is not authorized to perform this operation */ @Override public RequestStatus updateResources(Request request, Predicate predicate) throws SystemException, UnsupportedPropertyException, NoSuchResourceException, NoSuchParentResourceException { Authentication authentication = AuthorizationHelper.getAuthentication(); if (authentication == null || !authentication.isAuthenticated()) { throw new AuthorizationException("Authentication data is not available, authorization to perform the requested operation is not granted"); } else if (!isAuthorizedToUpdateResources(authentication, request, predicate)) { throw new AuthorizationException("The authenticated user does not have the appropriate authorizations to update the requested resource(s)"); } return updateResourcesAuthorized(request, predicate); } /** * Delete the resources selected by the given predicate. * <p/> * This implementation attempts to authorize the authenticated user before performing the requested * operation. If authorization fails, an AuthorizationException will be thrown. * <p/> * This method may be overwritten by implementing classes to avoid performing authorization checks * to delete resources. * * * @param request * @param predicate the predicate object which can be used to filter which * resources are deleted * @return the request status * @throws SystemException an internal system exception occurred * @throws UnsupportedPropertyException the request contains unsupported property ids * @throws NoSuchResourceException the resource instance to be deleted doesn't exist * @throws NoSuchParentResourceException a parent resource of the resource doesn't exist * @throws AuthorizationException if the authenticated user is not authorized to perform this operation */ @Override public RequestStatus deleteResources(Request request, Predicate predicate) throws SystemException, UnsupportedPropertyException, NoSuchResourceException, NoSuchParentResourceException { Authentication authentication = AuthorizationHelper.getAuthentication(); if (authentication == null || !authentication.isAuthenticated()) { throw new AuthorizationException("Authentication data is not available, authorization to perform the requested operation is not granted"); } else if (!isAuthorizedToDeleteResources(authentication, predicate)) { throw new AuthorizationException("The authenticated user does not have the appropriate authorizations to delete the requested resource(s)"); } return deleteResourcesAuthorized(request, predicate); } // ----- ResourceProvider (end) -------------------------------------------- /** * Create the resources defined by the properties in the given request object if authorization was * granted to the authenticated user. * <p/> * This method must be overwritten if {@link #createResources(Request)} is not overwritten. * * @param request the request object which defines the set of properties for the resources to be created * @return the request status * @throws SystemException an internal system exception occurred * @throws UnsupportedPropertyException the request contains unsupported property ids * @throws ResourceAlreadyExistsException attempted to create a resource which already exists * @throws NoSuchParentResourceException a parent resource of the resource to create doesn't exist * @throws AuthorizationException if the authenticated user is not authorized to perform this operation * @see #createResources(Request) */ protected RequestStatus createResourcesAuthorized(Request request) throws SystemException, UnsupportedPropertyException, ResourceAlreadyExistsException, NoSuchParentResourceException { throw new UnsupportedOperationException("If createResources is not overwritten, then createResourcesAuthorized must be overwritten"); } /** * Tests authorization to create resources. * <p/> * Implementations should override this method to perform a more sophisticated authorization routine. * * @param authentication the authenticated user and associated access privileges * @param request the request object which defines the set of properties for the resources to be created * @return true if authorized; otherwise false * @throws SystemException if an internal system exception occurred */ protected boolean isAuthorizedToCreateResources(Authentication authentication, Request request) throws SystemException { return AuthorizationHelper.isAuthorized(authentication, getResourceType(request, null), getResourceId(request, null), requiredCreateAuthorizations); } /** * Get a set of {@link Resource resources} based on the given request and predicate * information if the authenticated user is authorized to do so. * <p/> * This method must be overwritten if {@link #getResources(Request, Predicate)} is not overwritten. * * @param request the request object which defines the desired set of properties * @param predicate the predicate object which can be used to filter which resources are returned * @return a set of resources based on the given request and predicate information * @throws SystemException an internal system exception occurred * @throws UnsupportedPropertyException the request contains unsupported property ids * @throws NoSuchResourceException the requested resource instance doesn't exist * @throws NoSuchParentResourceException a parent resource of the requested resource doesn't exist * @throws AuthorizationException if the authenticated user is not authorized to perform this operation * @see #getResources(Request, Predicate) */ protected Set<Resource> getResourcesAuthorized(Request request, Predicate predicate) throws SystemException, UnsupportedPropertyException, NoSuchResourceException, NoSuchParentResourceException { throw new UnsupportedOperationException("If getResources is not overwritten, then getResourcesAuthorized must be overwritten"); } /** * Tests authorization to get resources. * <p/> * Implementations should override this method to perform a more sophisticated authorization routine. * * @param authentication the authenticated user and associated access privileges * @param request the request object which defines the desired set of properties * @param predicate the predicate object which can be used to filter which resources are returned * @return true if authorized; otherwise false * @throws SystemException if an internal system exception occurred */ protected boolean isAuthorizedToGetResources(Authentication authentication, Request request, Predicate predicate) throws SystemException { return AuthorizationHelper.isAuthorized(authentication, getResourceType(request, predicate), getResourceId(request, predicate), requiredGetAuthorizations); } /** * Update the resources selected by the given predicate with the properties from the given request * object if the authenticated user is authorized to do so. * <p/> * This method must be overwritten if {@link #updateResources(Request, Predicate)} is not overwritten. * * @param request the request object which defines the set of properties for the resources to be updated * @param predicate the predicate object which can be used to filter which resources are updated * @return the request status * @throws SystemException an internal system exception occurred * @throws UnsupportedPropertyException the request contains unsupported property ids * @throws NoSuchResourceException the resource instance to be updated doesn't exist * @throws NoSuchParentResourceException a parent resource of the resource doesn't exist * @throws AuthorizationException if the authenticated user is not authorized to perform this operation * @see #updateResources(Request, Predicate) */ protected RequestStatus updateResourcesAuthorized(Request request, Predicate predicate) throws SystemException, UnsupportedPropertyException, NoSuchResourceException, NoSuchParentResourceException { throw new UnsupportedOperationException("If updateResources is not overwritten, then updateResourcesAuthorized must be overwritten"); } /** * Tests authorization to update resources * <p/> * Implementations should override this method to perform a more sophisticated authorization routine. * * @param authentication the authenticated user and associated access privileges * @param request the request object which defines the desired set of properties * @param predicate the predicate object which can be used to filter which resources are returned * @return true if authorized; otherwise false * @throws SystemException if an internal system exception occurred */ protected boolean isAuthorizedToUpdateResources(Authentication authentication, Request request, Predicate predicate) throws SystemException { return AuthorizationHelper.isAuthorized(authentication, getResourceType(request, predicate), getResourceId(request, predicate), requiredUpdateAuthorizations); } /** * Delete the resources selected by the given predicate if the authenticated user is authorized * to do so. * <p/> * This method must be overwritten if {@link ResourceProvider#deleteResources(Request, Predicate)} is not overwritten. * * * @param request * @param predicate the predicate object which can be used to filter which resources are deleted * @return the request status * @throws SystemException an internal system exception occurred * @throws UnsupportedPropertyException the request contains unsupported property ids * @throws NoSuchResourceException the resource instance to be deleted doesn't exist * @throws NoSuchParentResourceException a parent resource of the resource doesn't exist * @throws AuthorizationException if the authenticated user is not authorized to perform this operation * @see ResourceProvider#deleteResources(Request, Predicate) */ protected RequestStatus deleteResourcesAuthorized(Request request, Predicate predicate) throws SystemException, UnsupportedPropertyException, NoSuchResourceException, NoSuchParentResourceException { throw new UnsupportedOperationException("If deleteResources is not overwritten, then deleteResourcesAuthorized must be overwritten"); } /** * Tests authorization to delete resources. * <p/> * Implementations should override this method to perform a more sophisticated authorization routine. * * @param authentication the authenticated user and associated access privileges * @param predicate the predicate object which can be used to filter which resources are deleted * @return true if authorized; otherwise false * @throws SystemException if an internal system exception occurred */ protected boolean isAuthorizedToDeleteResources(Authentication authentication, Predicate predicate) throws SystemException { return AuthorizationHelper.isAuthorized(authentication, getResourceType(null, predicate), getResourceId(null, predicate), requiredDeleteAuthorizations); } /** * Gets the ResourceType that is effected by the relevant request and predicate. * <p/> * Implementations should override this method return the proper ResourceType. * * @param request the request object which defines the desired set of properties * @param predicate the predicate object which can be used to indicate the filter * @return a ResourceType */ protected ResourceType getResourceType(Request request, Predicate predicate) { return ResourceType.CLUSTER; } /** * Gets the identifier, relative to the the effected ResourceType that is effected by the relevant * request and predicate. * <p/> * Implementations should override this method return the proper resource id. * * @param request the request object which defines the desired set of properties * @param predicate the predicate object which can be used to indicate the filter * @return a resource id; or null to indicate any or all resources of the relevant type */ protected Long getResourceId(Request request, Predicate predicate) { return null; } /** * Safely create an unmodifiable set of RoleAuthorizations * * @param set the set to copy * @return an unmodifiable set of RoleAuthorizations */ private Set<RoleAuthorization> createUnmodifiableSet(Set<RoleAuthorization> set) { return (set == null) ? Collections.<RoleAuthorization>emptySet() : Collections.unmodifiableSet(new HashSet<>(set)); } }