content: /*
   * 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.EnumSet;
  import java.util.Set;
  
  import org.apache.ambari.server.orm.entities.AlertCurrentEntity;
  import org.apache.ambari.server.orm.entities.AlertDefinitionEntity;
  import org.apache.ambari.server.orm.entities.AlertGroupEntity;
  import org.apache.ambari.server.orm.entities.AlertHistoryEntity;
  import org.apache.ambari.server.orm.entities.ClusterEntity;
  import org.apache.ambari.server.orm.entities.ResourceEntity;
  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.apache.commons.lang.StringUtils;
  
  /**
   * AlertResourceProviderUtils provides utility methods used to help perform tasks within alert-specific
   * resource providers.
   */
  public class AlertResourceProviderUtils {
  
    /**
     * A set of RoleAuthorizations where one is required in order to be authorized to view
     * cluster-level alerts
     */
    private static final Set<RoleAuthorization> AUTHORIZATIONS_VIEW_CLUSTER_ALERTS = EnumSet.of(
        RoleAuthorization.CLUSTER_VIEW_ALERTS,
        RoleAuthorization.CLUSTER_TOGGLE_ALERTS,
        RoleAuthorization.CLUSTER_MANAGE_ALERTS);
  
    /**
     * A set of RoleAuthorizations where one is required in order to be authorized to view
     * service-level alerts
     */
    private static final Set<RoleAuthorization> AUTHORIZATIONS_VIEW_SERVICE_ALERTS = EnumSet.of(
        RoleAuthorization.CLUSTER_VIEW_ALERTS,
        RoleAuthorization.CLUSTER_TOGGLE_ALERTS,
        RoleAuthorization.CLUSTER_MANAGE_ALERTS,
        RoleAuthorization.SERVICE_VIEW_ALERTS,
        RoleAuthorization.SERVICE_TOGGLE_ALERTS,
        RoleAuthorization.SERVICE_MANAGE_ALERTS);
  
    /**
     * A set of RoleAuthorizations where one is required in order to be authorized to execute
     * cluster-level alerts
     */
    private static final Set<RoleAuthorization> AUTHORIZATIONS_EXECUTE_CLUSTER_ALERTS = AUTHORIZATIONS_VIEW_CLUSTER_ALERTS;
  
    /**
     * A set of RoleAuthorizations where one is required in order to be authorized to execute
     * service-level alerts
     */
    private static final Set<RoleAuthorization> AUTHORIZATIONS_EXECUTE_SERVICE_ALERTS = AUTHORIZATIONS_VIEW_SERVICE_ALERTS;
  
    /**
     * A set of RoleAuthorizations where one is required in order to be authorized to toggle
     * cluster-level alerts
     */
    private static final Set<RoleAuthorization> AUTHORIZATIONS_TOGGLE_CLUSTER_ALERTS = EnumSet.of(
        RoleAuthorization.CLUSTER_TOGGLE_ALERTS,
        RoleAuthorization.CLUSTER_MANAGE_ALERTS);
  
    /**
     * A set of RoleAuthorizations where one is required in order to be authorized to toggle
     * service-level alerts
     */
    private static final Set<RoleAuthorization> AUTHORIZATIONS_TOGGLE_SERVICE_ALERTS = EnumSet.of(
        RoleAuthorization.CLUSTER_TOGGLE_ALERTS,
        RoleAuthorization.CLUSTER_MANAGE_ALERTS,
        RoleAuthorization.SERVICE_TOGGLE_ALERTS,
        RoleAuthorization.SERVICE_MANAGE_ALERTS);
  
    /**
     * A set of RoleAuthorizations where one is required in order to be authorized to create, update,
     * and delete cluster-level alerts
     */
    private static final Set<RoleAuthorization> AUTHORIZATIONS_MANAGE_CLUSTER_ALERTS = EnumSet.of(
        RoleAuthorization.CLUSTER_MANAGE_ALERTS);
  
    /**
     * A set of RoleAuthorizations where one is required in order to be authorized to create, update,
     * and delete service-level alerts
     */
    private static final Set<RoleAuthorization> AUTHORIZATIONS_MANAGE_SERVICE_ALERTS = EnumSet.of(
        RoleAuthorization.CLUSTER_MANAGE_ALERTS,
        RoleAuthorization.SERVICE_MANAGE_ALERTS);
  
  
    /* ------------------------------------------------------------------------------------------
     * Checks for VIEWING Alerts
     * ------------------------------------------------------------------------------------------   */
  
    /**
     * Tests if the authenticated user is authorized to view the requested alert data
     *
     * @param entity            an AlertGroupEntity
     * @param clusterResourceId the resource id of the relevant cluster
     * @return true if the authenticated user is authorized; otherwise false
     */
    public static boolean hasViewAuthorization(AlertGroupEntity entity, Long clusterResourceId) {
      return (null != entity) &&
          hasViewAuthorization(entity.getServiceName(), clusterResourceId);
    }
  
    /**
     * Tests if the authenticated user is authorized to view service- or cluster-level alert data
     *
     * @param serviceName       the name of the relevant service - null or empty indicates a cluster-level alert
     * @param clusterResourceId the resource id of the relevant cluster
     * @return true if the authenticated user is authorized; otherwise false
     */
    public static boolean hasViewAuthorization(String serviceName, Long clusterResourceId) {
      return hasAuthorization(serviceName, clusterResourceId,
          AUTHORIZATIONS_VIEW_CLUSTER_ALERTS, AUTHORIZATIONS_VIEW_SERVICE_ALERTS);
    }
  
    /**
     * Tests if the authenticated user is authorized to view service- or cluster-level alert data.
     * An authorization failure results in a thrown {@link AuthorizationException}.
     *
     * @param entity an AlertCurrentEntity
     * @throws AuthorizationException if the authenticated user is not authorized
     */
    public static void verifyViewAuthorization(AlertCurrentEntity entity)
        throws AuthorizationException {
      if (entity != null) {
        verifyViewAuthorization(entity.getAlertHistory());
      }
    }
  
    /**
     * Tests if the authenticated user is authorized to view service- or cluster-level alert data.
     * An authorization failure results in a thrown {@link AuthorizationException}.
     *
     * @param entity an AlertHistoryEntity
     * @throws AuthorizationException if the authenticated user is not authorized
     */
    public static void verifyViewAuthorization(AlertHistoryEntity entity)
        throws AuthorizationException {
      if (entity != null) {
        verifyViewAuthorization(entity.getAlertDefinition());
      }
    }
  
    /**
     * Tests if the authenticated user is authorized to view service- or cluster-level alert data.
     * An authorization failure results in a thrown {@link AuthorizationException}.
     *
     * @param entity            an AlertGroupEntity
     * @param clusterResourceId the resource id of the relevant cluster
     * @throws AuthorizationException if the authenticated user is not authorized
     */
    public static void verifyViewAuthorization(AlertGroupEntity entity, Long clusterResourceId)
        throws AuthorizationException {
      if (entity != null) {
        verifyViewAuthorization(entity.getServiceName(), clusterResourceId);
      }
    }
  
    /**
     * Tests if the authenticated user is authorized to view service- or cluster-level alert data.
     * An authorization failure results in a thrown {@link AuthorizationException}.
     *
     * @param entity an AlertDefinitionEntity
     * @throws AuthorizationException if the authenticated user is not authorized
     */
    public static void verifyViewAuthorization(AlertDefinitionEntity entity) throws AuthorizationException {
      verifyAuthorization(entity, AUTHORIZATIONS_VIEW_CLUSTER_ALERTS, AUTHORIZATIONS_VIEW_SERVICE_ALERTS, "view");
    }
  
    /**
     * Tests if the authenticated user is authorized to view service- or cluster-level alert data.
     * An authorization failure results in a thrown {@link AuthorizationException}.
     *
     * @param serviceName       the name of the relevant service - null or empty indicates a cluster-level alert
     * @param clusterResourceId the resource id of the relevant cluster
     * @throws AuthorizationException if the authenticated user is not authorized
     */
    public static void verifyViewAuthorization(String serviceName, Long clusterResourceId) throws AuthorizationException {
      verifyAuthorization(serviceName, clusterResourceId, AUTHORIZATIONS_VIEW_CLUSTER_ALERTS, AUTHORIZATIONS_VIEW_SERVICE_ALERTS, "view");
    }
  
  
    /* ------------------------------------------------------------------------------------------
     * Checks for EXECUTING Alerts
     * ------------------------------------------------------------------------------------------   */
  
    /**
     * Tests if the authenticated user is authorized to execute service- or cluster-level alert data.
     * An authorization failure results in a thrown {@link AuthorizationException}.
     *
     * @param entity an AlertDefinitionEntity
     * @throws AuthorizationException if the authenticated user is not authorized
     */
    public static void verifyExecuteAuthorization(AlertDefinitionEntity entity) throws AuthorizationException {
      verifyAuthorization(entity, AUTHORIZATIONS_EXECUTE_CLUSTER_ALERTS, AUTHORIZATIONS_EXECUTE_SERVICE_ALERTS, "execute");
    }
  
    /**
     * Tests if the authenticated user is authorized to execute service- or cluster-level alert data.
     * An authorization failure results in a thrown {@link AuthorizationException}.
     *
     * @param serviceName       the name of the relevant service - null or empty indicates a cluster-level alert
     * @param clusterResourceId the resource id of the relevant cluster
     * @throws AuthorizationException if the authenticated user is not authorized
     */
    public static void verifyExecuteAuthorization(String serviceName, Long clusterResourceId) throws AuthorizationException {
      verifyAuthorization(serviceName, clusterResourceId, AUTHORIZATIONS_EXECUTE_CLUSTER_ALERTS, AUTHORIZATIONS_EXECUTE_SERVICE_ALERTS, "execute");
    }
  
  
    /* ------------------------------------------------------------------------------------------
     * Checks for TOGGLING Alerts
     * ------------------------------------------------------------------------------------------   */
  
    /**
     * Tests if the authenticated user is authorized to toggle service- or cluster-level alert data.
     * An authorization failure results in a thrown {@link AuthorizationException}.
     *
     * @param entity an AlertDefinitionEntity
     * @throws AuthorizationException if the authenticated user is not authorized
     */
    public static void verifyToggleAuthorization(AlertDefinitionEntity entity) throws AuthorizationException {
      verifyAuthorization(entity, AUTHORIZATIONS_TOGGLE_CLUSTER_ALERTS, AUTHORIZATIONS_TOGGLE_SERVICE_ALERTS, "execute");
    }
  
    /**
     * Tests if the authenticated user is authorized to toggle service- or cluster-level alert data.
     * An authorization failure results in a thrown {@link AuthorizationException}.
     *
     * @param serviceName       the name of the relevant service - null or empty indicates a cluster-level alert
     * @param clusterResourceId the resource id of the relevant cluster
     * @throws AuthorizationException if the authenticated user is not authorized
     */
    public static void verifyToggleAuthorization(String serviceName, Long clusterResourceId) throws AuthorizationException {
      verifyAuthorization(serviceName, clusterResourceId, AUTHORIZATIONS_TOGGLE_CLUSTER_ALERTS, AUTHORIZATIONS_TOGGLE_SERVICE_ALERTS, "execute");
    }
  
  
    /* ------------------------------------------------------------------------------------------
     * Checks for MANAGING Alerts
     * ------------------------------------------------------------------------------------------   */
  
    /**
     * Tests if the authenticated user is authorized to manage service- or cluster-level alert data.
     * An authorization failure results in a thrown {@link AuthorizationException}.
     *
     * @param entity            an AlertGroupEntity
     * @param clusterResourceId the resource id of the relevant cluster
     * @throws AuthorizationException if the authenticated user is not authorized
     */
    public static void verifyManageAuthorization(AlertGroupEntity entity, Long clusterResourceId) throws AuthorizationException {
      if (entity != null) {
        verifyManageAuthorization(entity.getServiceName(), clusterResourceId);
      }
    }
  
    /**
     * Tests if the authenticated user is authorized to manage service- or cluster-level alert data.
     * An authorization failure results in a thrown {@link AuthorizationException}.
     *
     * @param entity an AlertDefinitionEntity
     * @throws AuthorizationException if the authenticated user is not authorized
     */
    public static void verifyManageAuthorization(AlertDefinitionEntity entity) throws AuthorizationException {
      verifyAuthorization(entity, AUTHORIZATIONS_MANAGE_CLUSTER_ALERTS, AUTHORIZATIONS_MANAGE_SERVICE_ALERTS, "manage");
    }
  
    /**
     * Tests if the authenticated user is authorized to manage service- or cluster-level alert data.
     * An authorization failure results in a thrown {@link AuthorizationException}.
     *
     * @param serviceName       the name of the relevant service - null or empty indicates a cluster-level alert
     * @param clusterResourceId the resource id of the relevant cluster
     * @throws AuthorizationException if the authenticated user is not authorized
     */
    public static void verifyManageAuthorization(String serviceName, Long clusterResourceId) throws AuthorizationException {
      verifyAuthorization(serviceName, clusterResourceId, AUTHORIZATIONS_MANAGE_CLUSTER_ALERTS, AUTHORIZATIONS_MANAGE_SERVICE_ALERTS, "manage");
    }
  
  
    /* ------------------------------------------------------------------------------------------
     * Generic checks
     * ------------------------------------------------------------------------------------------   */
  
    /**
     * Tests if the authenticated user is authorized to for either service- or cluster-level access to
     * alert data.
     * <p/>
     * If the service name is null or empty, the alert is considered to be a cluster-level alert,
     * else it is considered to be a service-level alert.
     * <p/>
     * If the clusterResourceId is null, no cluster is assume and the alert is considered to be an
     * Ambari-level alert.
     *
     * @param serviceName                the name of the relevant service - null or empty indicates a cluster-level alert
     * @param clusterResourceId          the resource id of the relevant cluster
     * @param clusterLevelAuthorizations the set of cluster-level authorizations to check for
     * @param serviceLevelAuthorizations the set of service-level authorizations to check for
     * @return true if the authenticated user is authorized; otherwise false
     */
    public static boolean hasAuthorization(String serviceName, Long clusterResourceId,
                                           Set<RoleAuthorization> clusterLevelAuthorizations,
                                           Set<RoleAuthorization> serviceLevelAuthorizations) {
      if (null == clusterResourceId) {
        // Do not let clusterResourceId be null because that indicates we don't care about which cluster
        // we are checking authorization for, but we do.  Setting this to -1 ensures that no cluster
        // will match will will give only Ambari administrators access to this.
        clusterResourceId = -1L;
      }
  
      return AuthorizationHelper.isAuthorized(ResourceType.CLUSTER, clusterResourceId,
          (StringUtils.isEmpty(serviceName) || "AMBARI".equals(serviceName))
              ? clusterLevelAuthorizations
              : serviceLevelAuthorizations);
    }
  
    /**
     * Tests if the authenticated user is authorized to for either service- or cluster-level access to
     * alert data. An authorization failure results in a thrown {@link AuthorizationException}.
     * <p/>
     * If the service name from the AlertDefinitionEntity is null or empty, the alert is considered to
     * be a cluster-level alert, else it is considered to be a service-level alert.
     *
     * @param entity                     an AlertDefinitionEntity
     * @param clusterLevelAuthorizations the set of cluster-level authorizations to check for
     * @param serviceLevelAuthorizations the set of service-level authorizations to check for
     * @param operation                  the name of the operation being tested for (used in error and logging messages)
     * @throws AuthorizationException if the authenticated user is not authorized
     * @see #verifyAuthorization(String, Long, Set, Set, String)
     */
    public static void verifyAuthorization(AlertDefinitionEntity entity,
                                           Set<RoleAuthorization> clusterLevelAuthorizations,
                                           Set<RoleAuthorization> serviceLevelAuthorizations,
                                           String operation) throws AuthorizationException {
      ClusterEntity clusterEntity = (null == entity) ? null : entity.getCluster();
      ResourceEntity resourceEntity = (null == clusterEntity) ? null : clusterEntity.getResource();
      Long resourceId = (null == resourceEntity) ? null : resourceEntity.getId();
  
      verifyAuthorization((null == entity) ? null : entity.getServiceName(), resourceId,
          clusterLevelAuthorizations, serviceLevelAuthorizations, operation);
    }
  
    /**
     * Tests if the authenticated user is authorized to for either service- or cluster-level access to
     * alert data. An authorization failure results in a thrown {@link AuthorizationException}.
     * <p/>
     * If the service name from the AlertDefinitionEntity is null or empty, the alert is considered to
     * be a cluster-level alert, else it is considered to be a service-level alert.
     *
     * @param serviceName                the name of the relevant service - null or empty indicates a cluster-level alert
     * @param clusterResourceId          the resource id of the relevant cluster
     * @param clusterLevelAuthorizations the set of cluster-level authorizations to check for
     * @param serviceLevelAuthorizations the set of service-level authorizations to check for
     * @param operation                  the name of the operation being tested for (used in error and logging messages)
     * @throws AuthorizationException if the authenticated user is not authorized
     */
    public static void verifyAuthorization(String serviceName, Long clusterResourceId,
                                           Set<RoleAuthorization> clusterLevelAuthorizations,
                                           Set<RoleAuthorization> serviceLevelAuthorizations,
                                           String operation) throws AuthorizationException {
      if (null == clusterResourceId) {
        // Do not let clusterResourceId be null because that indicates we don't care about which cluster
        // we are checking authorization for, but we do.  Setting this to -1 ensures that no cluster
        // will match will will give only Ambari administrators access to this.
        clusterResourceId = -1L;
      }
  
      // If the service name is AMBARI, than the alert is for the cluster
      if (StringUtils.isEmpty(serviceName) || "AMBARI".equals(serviceName)) {
        if (!AuthorizationHelper.isAuthorized(ResourceType.CLUSTER, clusterResourceId,
            clusterLevelAuthorizations)) {
          throw new AuthorizationException(String.format("The authenticated user is not authorized to %s cluster-level alerts", operation));
        }
      } else {
        if (!AuthorizationHelper.isAuthorized(ResourceType.CLUSTER, clusterResourceId,
            serviceLevelAuthorizations)) {
          throw new AuthorizationException(String.format("The authenticated user is not authorized to %s service-level alerts", operation));
        }
      }
    }
  }
  
  