You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@ambari.apache.org by rl...@apache.org on 2015/12/10 16:42:19 UTC

[2/2] ambari git commit: AMBARI-14193. Enforce granular role-based access control for host functions (rlevas)

AMBARI-14193. Enforce granular role-based access control for host functions (rlevas)


Project: http://git-wip-us.apache.org/repos/asf/ambari/repo
Commit: http://git-wip-us.apache.org/repos/asf/ambari/commit/5de1d054
Tree: http://git-wip-us.apache.org/repos/asf/ambari/tree/5de1d054
Diff: http://git-wip-us.apache.org/repos/asf/ambari/diff/5de1d054

Branch: refs/heads/trunk
Commit: 5de1d0547c087a863fb488778c38b781ee7c33e1
Parents: 8750537
Author: Robert Levas <rl...@hortonworks.com>
Authored: Thu Dec 10 10:42:08 2015 -0500
Committer: Robert Levas <rl...@hortonworks.com>
Committed: Thu Dec 10 10:42:08 2015 -0500

----------------------------------------------------------------------
 .../internal/HostResourceProvider.java          |  80 +-
 .../AmbariAuthorizationFilter.java              |   2 +
 .../internal/HostResourceProviderTest.java      | 916 +++++++++++--------
 3 files changed, 579 insertions(+), 419 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/ambari/blob/5de1d054/ambari-server/src/main/java/org/apache/ambari/server/controller/internal/HostResourceProvider.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/java/org/apache/ambari/server/controller/internal/HostResourceProvider.java b/ambari-server/src/main/java/org/apache/ambari/server/controller/internal/HostResourceProvider.java
index 39d4040..8f00321 100644
--- a/ambari-server/src/main/java/org/apache/ambari/server/controller/internal/HostResourceProvider.java
+++ b/ambari-server/src/main/java/org/apache/ambari/server/controller/internal/HostResourceProvider.java
@@ -20,6 +20,7 @@ package org.apache.ambari.server.controller.internal;
 import java.text.MessageFormat;
 import java.util.ArrayList;
 import java.util.Arrays;
+import java.util.Collections;
 import java.util.EnumSet;
 import java.util.HashMap;
 import java.util.HashSet;
@@ -49,6 +50,10 @@ 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.controller.utilities.PropertyHelper;
+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.ambari.server.state.Cluster;
 import org.apache.ambari.server.state.Clusters;
 import org.apache.ambari.server.state.Config;
@@ -62,7 +67,6 @@ import org.apache.ambari.server.state.stack.OsFamily;
 import org.apache.ambari.server.topology.InvalidTopologyException;
 import org.apache.ambari.server.topology.InvalidTopologyTemplateException;
 import org.apache.ambari.server.topology.TopologyManager;
-import org.apache.ambari.server.topology.TopologyRequest;
 import org.apache.commons.lang.StringUtils;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
@@ -167,12 +171,19 @@ public class HostResourceProvider extends AbstractControllerResourceProvider {
                        @Assisted Map<Resource.Type, String> keyPropertyIds,
                        @Assisted AmbariManagementController managementController) {
     super(propertyIds, keyPropertyIds, managementController);
+
+    Set<RoleAuthorization> authorizationsAddDelete = EnumSet.of(RoleAuthorization.HOST_ADD_DELETE_HOSTS);
+
+    setRequiredCreateAuthorizations(authorizationsAddDelete);
+    setRequiredDeleteAuthorizations(authorizationsAddDelete);
+    setRequiredGetAuthorizations(RoleAuthorization.AUTHORIZATIONS_VIEW_CLUSTER);
+    setRequiredUpdateAuthorizations(RoleAuthorization.AUTHORIZATIONS_UPDATE_CLUSTER);
   }
 
   // ----- ResourceProvider ------------------------------------------------
 
   @Override
-  public RequestStatus createResources(final Request request)
+  protected RequestStatus createResourcesAuthorized(final Request request)
       throws SystemException,
           UnsupportedPropertyException,
           ResourceAlreadyExistsException,
@@ -196,7 +207,7 @@ public class HostResourceProvider extends AbstractControllerResourceProvider {
   }
 
   @Override
-  public Set<Resource> getResources(Request request, Predicate predicate)
+  protected Set<Resource> getResourcesAuthorized(Request request, Predicate predicate)
       throws SystemException, UnsupportedPropertyException, NoSuchResourceException, NoSuchParentResourceException {
 
     final Set<HostRequest> requests = new HashSet<HostRequest>();
@@ -289,7 +300,7 @@ public class HostResourceProvider extends AbstractControllerResourceProvider {
   }
 
   @Override
-  public RequestStatus updateResources(final Request request, Predicate predicate)
+  protected RequestStatus updateResourcesAuthorized(final Request request, Predicate predicate)
       throws SystemException, UnsupportedPropertyException, NoSuchResourceException, NoSuchParentResourceException {
 
     final Set<HostRequest> requests = new HashSet<HostRequest>();
@@ -299,7 +310,7 @@ public class HostResourceProvider extends AbstractControllerResourceProvider {
 
     modifyResources(new Command<Void>() {
       @Override
-      public Void invoke() throws AmbariException {
+      public Void invoke() throws AmbariException, AuthorizationException {
         updateHosts(requests);
         return null;
       }
@@ -311,7 +322,7 @@ public class HostResourceProvider extends AbstractControllerResourceProvider {
   }
 
   @Override
-  public RequestStatus deleteResources(Predicate predicate)
+  protected RequestStatus deleteResourcesAuthorized(Predicate predicate)
       throws SystemException, UnsupportedPropertyException, NoSuchResourceException, NoSuchParentResourceException {
 
     final Set<HostRequest> requests = new HashSet<HostRequest>();
@@ -647,7 +658,7 @@ public class HostResourceProvider extends AbstractControllerResourceProvider {
     return response;
   }
 
-  protected synchronized void updateHosts(Set<HostRequest> requests) throws AmbariException {
+  protected synchronized void updateHosts(Set<HostRequest> requests) throws AmbariException, AuthorizationException {
 
     if (requests.isEmpty()) {
       LOG.warn("Received an empty requests set");
@@ -673,6 +684,8 @@ public class HostResourceProvider extends AbstractControllerResourceProvider {
       Host host = clusters.getHost(request.getHostname());
 
       String clusterName = request.getClusterName();
+      Cluster cluster = clusters.getCluster(clusterName);
+      Long clusterId = cluster.getClusterId();
 
       try {
         // The below method call throws an exception when trying to create a duplicate mapping in the clusterhostmapping
@@ -683,6 +696,9 @@ public class HostResourceProvider extends AbstractControllerResourceProvider {
       }
 
       if (null != request.getHostAttributes()) {
+        if(!AuthorizationHelper.isAuthorized(ResourceType.CLUSTER, clusterId, RoleAuthorization.HOST_ADD_DELETE_HOSTS)) {
+          throw new AuthorizationException("The authenticated user is not authorized to update host attributes");
+        }
         host.setHostAttributes(request.getHostAttributes());
       }
 
@@ -691,35 +707,64 @@ public class HostResourceProvider extends AbstractControllerResourceProvider {
       boolean rackChange      = requestRackInfo != null && !requestRackInfo.equals(rackInfo);
 
       if (rackChange) {
+        if(!AuthorizationHelper.isAuthorized(ResourceType.CLUSTER, clusterId, RoleAuthorization.HOST_ADD_DELETE_HOSTS)) {
+          throw new AuthorizationException("The authenticated user is not authorized to update host rack information");
+        }
         host.setRackInfo(requestRackInfo);
       }
 
       if (null != request.getPublicHostName()) {
+        if(!AuthorizationHelper.isAuthorized(ResourceType.CLUSTER, clusterId, RoleAuthorization.HOST_ADD_DELETE_HOSTS)) {
+          throw new AuthorizationException("The authenticated user is not authorized to update host attributes");
+        }
         host.setPublicHostName(request.getPublicHostName());
       }
       
       if (null != clusterName && null != request.getMaintenanceState()) {
-        Cluster c = clusters.getCluster(clusterName);
+        if(!AuthorizationHelper.isAuthorized(ResourceType.CLUSTER, clusterId, RoleAuthorization.HOST_TOGGLE_MAINTENANCE)) {
+          throw new AuthorizationException("The authenticated user is not authorized to update host maintenance state");
+        }
         MaintenanceState newState = MaintenanceState.valueOf(request.getMaintenanceState());
-        MaintenanceState oldState = host.getMaintenanceState(c.getClusterId());
+        MaintenanceState oldState = host.getMaintenanceState(clusterId);
         if (!newState.equals(oldState)) {
           if (newState.equals(MaintenanceState.IMPLIED_FROM_HOST)
               || newState.equals(MaintenanceState.IMPLIED_FROM_SERVICE)) {
             throw new IllegalArgumentException("Invalid arguments, can only set " +
               "maintenance state to one of " + EnumSet.of(MaintenanceState.OFF, MaintenanceState.ON));
           } else {
-            host.setMaintenanceState(c.getClusterId(), newState);
+            host.setMaintenanceState(clusterId, newState);
           }
         }
       }
 
       // Create configurations
       if (null != clusterName && null != request.getDesiredConfigs()) {
-        Cluster c = clusters.getCluster(clusterName);
-
         if (clusters.getHostsForCluster(clusterName).containsKey(host.getHostName())) {
 
           for (ConfigurationRequest cr : request.getDesiredConfigs()) {
+            String configType = cr.getType();
+
+            // If the config type is for a service, then allow a user with SERVICE_MODIFY_CONFIGS to
+            // update, else ensure the user has CLUSTER_MODIFY_CONFIGS
+            String service = null;
+
+            try {
+              service = cluster.getServiceForConfigTypes(Collections.singleton(configType));
+            } catch (IllegalArgumentException e) {
+              // Ignore this since we may have hit a config type that spans multiple services. This may
+              // happen in unit test cases but should not happen with later versions of stacks.
+            }
+
+            if(StringUtils.isEmpty(service)) {
+              if (!AuthorizationHelper.isAuthorized(ResourceType.CLUSTER, cluster.getClusterId(), EnumSet.of(RoleAuthorization.CLUSTER_MODIFY_CONFIGS))) {
+                throw new AuthorizationException("The authenticated user does not have authorization to modify cluster configurations");
+              }
+            }
+            else {
+              if (!AuthorizationHelper.isAuthorized(ResourceType.CLUSTER, cluster.getClusterId(), EnumSet.of(RoleAuthorization.SERVICE_MODIFY_CONFIGS))) {
+                throw new AuthorizationException("The authenticated user does not have authorization to modify service configurations");
+              }
+            }
 
             if (null != cr.getProperties() && cr.getProperties().size() > 0) {
               LOG.info(MessageFormat.format("Applying configuration with tag ''{0}'' to host ''{1}'' in cluster ''{2}''",
@@ -727,18 +772,18 @@ public class HostResourceProvider extends AbstractControllerResourceProvider {
                   request.getHostname(),
                   clusterName));
 
-              cr.setClusterName(c.getClusterName());
+              cr.setClusterName(cluster.getClusterName());
               controller.createConfiguration(cr);
             }
 
-            Config baseConfig = c.getConfig(cr.getType(), cr.getVersionTag());
+            Config baseConfig = cluster.getConfig(cr.getType(), cr.getVersionTag());
             if (null != baseConfig) {
               String authName = controller.getAuthName();
-              DesiredConfig oldConfig = host.getDesiredConfigs(c.getClusterId()).get(cr.getType());
+              DesiredConfig oldConfig = host.getDesiredConfigs(clusterId).get(cr.getType());
 
-              if (host.addDesiredConfig(c.getClusterId(), cr.isSelected(), authName,  baseConfig)) {
+              if (host.addDesiredConfig(clusterId, cr.isSelected(), authName,  baseConfig)) {
                 Logger logger = LoggerFactory.getLogger("configchange");
-                logger.info("cluster '" + c.getClusterName() + "', "
+                logger.info("cluster '" + cluster.getClusterName() + "', "
                     + "host '" + host.getHostName() + "' "
                     + "changed by: '" + authName + "'; "
                     + "type='" + baseConfig.getType() + "' "
@@ -754,6 +799,7 @@ public class HostResourceProvider extends AbstractControllerResourceProvider {
       if (clusterName != null && !clusterName.isEmpty()) {
         clusters.getCluster(clusterName).recalculateAllClusterVersionStates();
         if (rackChange) {
+          // Authorization check for this update was performed before we got to this point.
           controller.registerRackChange(clusterName);
         }
       }

http://git-wip-us.apache.org/repos/asf/ambari/blob/5de1d054/ambari-server/src/main/java/org/apache/ambari/server/security/authorization/AmbariAuthorizationFilter.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/java/org/apache/ambari/server/security/authorization/AmbariAuthorizationFilter.java b/ambari-server/src/main/java/org/apache/ambari/server/security/authorization/AmbariAuthorizationFilter.java
index 21745b4..5146cca 100644
--- a/ambari-server/src/main/java/org/apache/ambari/server/security/authorization/AmbariAuthorizationFilter.java
+++ b/ambari-server/src/main/java/org/apache/ambari/server/security/authorization/AmbariAuthorizationFilter.java
@@ -76,6 +76,7 @@ public class AmbariAuthorizationFilter implements Filter {
   private static final String API_CLUSTER_SERVICES_ALL_PATTERN = API_VERSION_PREFIX + "/clusters/.*?/services.*";
   private static final String API_HOSTS_ALL_PATTERN = API_VERSION_PREFIX + "/clusters/.*?/hosts.*";
   private static final String API_STACK_VERSIONS_PATTERN = API_VERSION_PREFIX + "/stacks/.*?/versions/.*";
+  private static final String API_HOSTS_ALL = API_VERSION_PREFIX + "/hosts.*";
 
   protected static final String LOGIN_REDIRECT_BASE = "/#/login?targetURI=";
 
@@ -265,6 +266,7 @@ public class AmbariAuthorizationFilter implements Filter {
         requestURI.matches(API_STACK_VERSIONS_PATTERN) ||
         requestURI.matches(API_WIDGET_LAYOUTS_PATTERN) ||
         requestURI.matches(API_HOSTS_ALL_PATTERN) ||
+        requestURI.matches(API_HOSTS_ALL) ||
         requestURI.matches(API_PRIVILEGES_ALL_PATTERN);
   }