ambari-commits mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From rle...@apache.org
Subject ambari git commit: AMBARI-16851. Cluster operator and cluster admin not allowed to install ambari agent (rlevas)
Date Fri, 27 May 2016 17:47:45 GMT
Repository: ambari
Updated Branches:
  refs/heads/branch-2.4 e22e2cbbe -> e7b852607


AMBARI-16851. Cluster operator and cluster admin not allowed to install ambari agent (rlevas)


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

Branch: refs/heads/branch-2.4
Commit: e7b852607fec810eb3bc4c0dc0cfedccdff395f4
Parents: e22e2cb
Author: Robert Levas <rlevas@hortonworks.com>
Authored: Fri May 27 13:47:35 2016 -0400
Committer: Robert Levas <rlevas@hortonworks.com>
Committed: Fri May 27 13:47:35 2016 -0400

----------------------------------------------------------------------
 .../internal/RequestResourceProvider.java       | 31 ++++++-
 .../server/customactions/ActionDefinition.java  | 16 +++-
 .../customactions/ActionDefinitionManager.java  | 37 ++++++++-
 .../customactions/ActionDefinitionSpec.java     | 10 +++
 .../AmbariAuthorizationFilter.java              | 87 +++++++++++---------
 .../server/upgrade/UpgradeCatalog240.java       | 13 +++
 .../main/resources/Ambari-DDL-Derby-CREATE.sql  |  1 +
 .../main/resources/Ambari-DDL-MySQL-CREATE.sql  |  1 +
 .../main/resources/Ambari-DDL-Oracle-CREATE.sql |  1 +
 .../resources/Ambari-DDL-Postgres-CREATE.sql    |  1 +
 .../Ambari-DDL-Postgres-EMBEDDED-CREATE.sql     |  1 +
 .../resources/Ambari-DDL-SQLAnywhere-CREATE.sql |  1 +
 .../resources/Ambari-DDL-SQLServer-CREATE.sql   |  1 +
 .../system_action_definitions.xml               |  1 +
 .../AmbariManagementControllerTest.java         | 18 ++--
 .../internal/ActionResourceProviderTest.java    |  8 +-
 .../internal/RequestResourceProviderTest.java   | 74 ++++++++++++++---
 .../ActionDefinitionManagerTest.java            | 29 ++++++-
 .../security/TestAuthenticationFactory.java     | 57 +++++++++++++
 .../server/upgrade/UpgradeCatalog240Test.java   |  3 +
 .../cust_action_definitions1.xml                |  9 ++
 .../cust_action_definitions_invalid.xml         | 33 ++++++++
 22 files changed, 366 insertions(+), 67 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/ambari/blob/e7b85260/ambari-server/src/main/java/org/apache/ambari/server/controller/internal/RequestResourceProvider.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/java/org/apache/ambari/server/controller/internal/RequestResourceProvider.java b/ambari-server/src/main/java/org/apache/ambari/server/controller/internal/RequestResourceProvider.java
index 5b318af..d38234f 100644
--- a/ambari-server/src/main/java/org/apache/ambari/server/controller/internal/RequestResourceProvider.java
+++ b/ambari-server/src/main/java/org/apache/ambari/server/controller/internal/RequestResourceProvider.java
@@ -56,6 +56,7 @@ import org.apache.ambari.server.controller.spi.SystemException;
 import org.apache.ambari.server.controller.spi.UnsupportedPropertyException;
 import org.apache.ambari.server.controller.utilities.PredicateBuilder;
 import org.apache.ambari.server.controller.utilities.PropertyHelper;
+import org.apache.ambari.server.customactions.ActionDefinition;
 import org.apache.ambari.server.orm.dao.HostRoleCommandDAO;
 import org.apache.ambari.server.orm.dao.HostRoleCommandStatusSummaryDTO;
 import org.apache.ambari.server.orm.dao.RequestDAO;
@@ -71,6 +72,7 @@ import org.apache.ambari.server.topology.TopologyManager;
 
 import com.google.common.collect.Sets;
 import com.google.inject.Inject;
+import org.apache.commons.lang.StringUtils;
 
 /**
  * Resource provider for request resources.
@@ -185,8 +187,33 @@ public class RequestResourceProvider extends AbstractControllerResourceProvider
         String clusterName = actionRequest.getClusterName();
 
         if(clusterName == null) {
-          // This must be an administrative action?
-          // TODO: Perform authorization check for this?
+          String actionName = actionRequest.getActionName();
+
+          // Ensure that the actionName is not null or empty.  A null actionName will result in
+          // a NPE at when getting the action definition.  The string "_unknown_action_" should not
+          // result in a valid action definition and should be easy to understand in any error message
+          // that gets displayed or logged due to an authorization issue.
+          if(StringUtils.isEmpty(actionName)) {
+            actionName = "_unknown_action_";
+          }
+
+          ActionDefinition actionDefinition = getManagementController().getAmbariMetaInfo().getActionDefinition(actionName);
+          Set<RoleAuthorization> permissions = (actionDefinition == null) ? null : actionDefinition.getPermissions();
+
+          if(permissions == null) {
+            if (!AuthorizationHelper.isAuthorized(ResourceType.AMBARI, null, RoleAuthorization.SERVICE_RUN_CUSTOM_COMMAND)) {
+              throw new AuthorizationException(String.format("The authenticated user is not authorized to execute the '%s'command.", actionName));
+            }
+          }
+          else {
+            // Since we cannot tell whether the action is to be exectued for the system or a
+            // non-disclosed cluster, specify that the resource is a CLUSTER with no resource id.
+            // This should ensure that a user with a role for any cluster with the appropriate
+            // permissions or an Ambari administrator can execute the command.
+            if (!AuthorizationHelper.isAuthorized(ResourceType.CLUSTER, null, permissions)) {
+              throw new AuthorizationException(String.format("The authenticated user is not authorized to execute the '%s'command.", actionName));
+            }
+          }
         }
         else if(actionRequest.isCommand()) {
           if (!AuthorizationHelper.isAuthorized(ResourceType.CLUSTER,

http://git-wip-us.apache.org/repos/asf/ambari/blob/e7b85260/ambari-server/src/main/java/org/apache/ambari/server/customactions/ActionDefinition.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/java/org/apache/ambari/server/customactions/ActionDefinition.java b/ambari-server/src/main/java/org/apache/ambari/server/customactions/ActionDefinition.java
index 1f189a3..02c469f 100644
--- a/ambari-server/src/main/java/org/apache/ambari/server/customactions/ActionDefinition.java
+++ b/ambari-server/src/main/java/org/apache/ambari/server/customactions/ActionDefinition.java
@@ -21,6 +21,9 @@ package org.apache.ambari.server.customactions;
 import org.apache.ambari.server.actionmanager.ActionType;
 import org.apache.ambari.server.actionmanager.TargetHostType;
 import org.apache.ambari.server.controller.ActionResponse;
+import org.apache.ambari.server.security.authorization.RoleAuthorization;
+
+import java.util.Set;
 
 /**
  * The resource describing the definition of an action
@@ -34,6 +37,7 @@ public class ActionDefinition {
   private String description;
   private TargetHostType targetType;
   private Short defaultTimeout;
+  private Set<RoleAuthorization> permissions;
 
   /**
    * Create an instance of ActionDefinition
@@ -46,10 +50,11 @@ public class ActionDefinition {
    * @param description     Short description of the action
    * @param targetType      Selection criteria for target hosts
    * @param defaultTimeout  The timeout value for this action when executed
+   * @param permissions     A set of permissions to use when verifiying authorization to execute this action
    */
   public ActionDefinition(String actionName, ActionType actionType, String inputs,
                           String targetService, String targetComponent, String description,
-                          TargetHostType targetType, Short defaultTimeout) {
+                          TargetHostType targetType, Short defaultTimeout, Set<RoleAuthorization> permissions) {
     setActionName(actionName);
     setActionType(actionType);
     setInputs(inputs);
@@ -58,6 +63,7 @@ public class ActionDefinition {
     setDescription(description);
     setTargetType(targetType);
     setDefaultTimeout(defaultTimeout);
+    setPermissions(permissions);
   }
 
   public String getActionName() {
@@ -124,6 +130,14 @@ public class ActionDefinition {
     this.defaultTimeout = defaultTimeout;
   }
 
+  public void setPermissions(Set<RoleAuthorization> permissions) {
+    this.permissions = permissions;
+  }
+
+  public Set<RoleAuthorization> getPermissions() {
+    return permissions;
+  }
+
   public ActionResponse convertToResponse() {
     return new ActionResponse(getActionName(), getActionType().name(), getInputs(),
         getTargetService(), getTargetComponent(), getDescription(), getTargetType().name(),

http://git-wip-us.apache.org/repos/asf/ambari/blob/e7b85260/ambari-server/src/main/java/org/apache/ambari/server/customactions/ActionDefinitionManager.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/java/org/apache/ambari/server/customactions/ActionDefinitionManager.java b/ambari-server/src/main/java/org/apache/ambari/server/customactions/ActionDefinitionManager.java
index 97aa8a0..637471f 100644
--- a/ambari-server/src/main/java/org/apache/ambari/server/customactions/ActionDefinitionManager.java
+++ b/ambari-server/src/main/java/org/apache/ambari/server/customactions/ActionDefinitionManager.java
@@ -21,6 +21,8 @@ import org.apache.ambari.server.AmbariException;
 import org.apache.ambari.server.actionmanager.ActionType;
 import org.apache.ambari.server.actionmanager.TargetHostType;
 import org.apache.ambari.server.api.services.AmbariMetaInfo;
+import org.apache.ambari.server.security.authorization.RoleAuthorization;
+import org.apache.commons.lang.StringUtils;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
@@ -30,9 +32,12 @@ import javax.xml.bind.UnmarshalException;
 import javax.xml.bind.Unmarshaller;
 import java.io.File;
 import java.util.ArrayList;
+import java.util.EnumSet;
 import java.util.HashMap;
+import java.util.HashSet;
 import java.util.List;
 import java.util.Map;
+import java.util.Set;
 
 /**
  * Manages Action definitions read from XML files
@@ -120,7 +125,8 @@ public class ActionDefinitionManager {
             }
 
             actionDefinitionMap.put(ad.getActionName(), new ActionDefinition(ad.getActionName(), actionType,
-                ad.getInputs(), ad.getTargetService(), ad.getTargetComponent(), ad.getDescription(), targetType, defaultTimeout));
+                ad.getInputs(), ad.getTargetService(), ad.getTargetComponent(), ad.getDescription(), targetType, defaultTimeout,
+                translatePermissions(ad.getPermissions())));
             LOG.info("Added custom action definition for " + ad.getActionName());
           } else {
             LOG.warn(errorReason.toString());
@@ -199,4 +205,33 @@ public class ActionDefinitionManager {
     }
     return true;
   }
+
+  /**
+   * Given a comma-delimited list of permission names, translates into a {@link Set} of
+   * {@link RoleAuthorization}s.
+   * <p>
+   * <code>null</code> is returned if the permission string is null or empty, or if none of the
+   * permissions in the string translate to a {@link RoleAuthorization}.  Permissions that do not
+   * translate to a {@link RoleAuthorization} will yield a {@link IllegalArgumentException}.
+   *
+   * @param permissions a comma-delimited string of permission names
+   * @return a set of {@link RoleAuthorization}s; or null if no permissions are specified
+   */
+  private Set<RoleAuthorization> translatePermissions(String permissions) {
+    if (StringUtils.isEmpty(permissions)) {
+      return null;
+    } else {
+      Set<RoleAuthorization> authorizations = new HashSet<RoleAuthorization>();
+      String[] parts = permissions.split(",");
+
+      for (String permission : parts) {
+        RoleAuthorization authorization = RoleAuthorization.translate(permission);
+        if (authorization != null) {
+          authorizations.add(authorization);
+        }
+      }
+
+      return (authorizations.isEmpty()) ? null : EnumSet.copyOf(authorizations);
+    }
+  }
 }

http://git-wip-us.apache.org/repos/asf/ambari/blob/e7b85260/ambari-server/src/main/java/org/apache/ambari/server/customactions/ActionDefinitionSpec.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/java/org/apache/ambari/server/customactions/ActionDefinitionSpec.java b/ambari-server/src/main/java/org/apache/ambari/server/customactions/ActionDefinitionSpec.java
index 2dfa1f2..f789691 100644
--- a/ambari-server/src/main/java/org/apache/ambari/server/customactions/ActionDefinitionSpec.java
+++ b/ambari-server/src/main/java/org/apache/ambari/server/customactions/ActionDefinitionSpec.java
@@ -27,6 +27,7 @@ public class ActionDefinitionSpec {
   private String description;
   private String targetType;
   private String defaultTimeout;
+  private String permissions;
 
   public String getTargetComponent() {
     return targetComponent;
@@ -92,6 +93,14 @@ public class ActionDefinitionSpec {
     this.targetService = targetService;
   }
 
+  public String getPermissions() {
+    return permissions;
+  }
+
+  public void setPermissions(String permissions) {
+    this.permissions = permissions;
+  }
+
   @Override
   public int hashCode() {
     final int prime = 31;
@@ -134,6 +143,7 @@ public class ActionDefinitionSpec {
         .append(" targetComponent: ").append(targetComponent)
         .append(" defaultTimeout: ").append(defaultTimeout)
         .append(" targetType: ").append(targetType)
+        .append(" permissions: ").append(permissions)
         .toString();
   }
 }

http://git-wip-us.apache.org/repos/asf/ambari/blob/e7b85260/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 5c74f07..eeb1a8b 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
@@ -47,6 +47,7 @@ import javax.servlet.http.HttpServletRequest;
 import javax.servlet.http.HttpServletResponse;
 import java.io.IOException;
 import java.security.Principal;
+import java.util.EnumSet;
 import java.util.regex.Pattern;
 
 public class AmbariAuthorizationFilter implements Filter {
@@ -77,9 +78,12 @@ public class AmbariAuthorizationFilter implements Filter {
   private static final String API_CLUSTER_SERVICES_ALL_PATTERN = API_VERSION_PREFIX + "/clusters/.*?/services.*";
   private static final String API_CLUSTER_ALERT_ALL_PATTERN = API_VERSION_PREFIX + "/clusters/.*?/alert.*";
   private static final String API_CLUSTER_HOSTS_ALL_PATTERN = API_VERSION_PREFIX + "/clusters/.*?/hosts.*";
+  private static final String API_CLUSTER_HOST_COMPONENTS_ALL_PATTERN = API_VERSION_PREFIX + "/clusters/.*?/host_components.*";
   private static final String API_STACK_VERSIONS_PATTERN = API_VERSION_PREFIX + "/stacks/.*?/versions/.*";
   private static final String API_HOSTS_ALL_PATTERN = API_VERSION_PREFIX + "/hosts.*";
   private static final String API_ALERT_TARGETS_ALL_PATTERN = API_VERSION_PREFIX + "/alert_targets.*";
+  private static final String API_BOOTSTRAP_PATTERN_ALL = API_VERSION_PREFIX + "/bootstrap.*";
+  private static final String API_REQUESTS_ALL_PATTERN = API_VERSION_PREFIX + "/requests.*";
 
   protected static final String LOGIN_REDIRECT_BASE = "/#/login?targetURI=";
 
@@ -161,55 +165,62 @@ public class AmbariAuthorizationFilter implements Filter {
     } else if (!authorizationPerformedInternally(requestURI)) {
       boolean authorized = false;
 
-      for (GrantedAuthority grantedAuthority : authentication.getAuthorities()) {
-        if (grantedAuthority instanceof AmbariGrantedAuthority) {
-
-          AmbariGrantedAuthority ambariGrantedAuthority = (AmbariGrantedAuthority) grantedAuthority;
+      if (requestURI.matches(API_BOOTSTRAP_PATTERN_ALL)) {
+        authorized = AuthorizationHelper.isAuthorized(authentication,
+            ResourceType.CLUSTER,
+            null,
+            EnumSet.of(RoleAuthorization.HOST_ADD_DELETE_HOSTS));
+      }
+      else {
+        for (GrantedAuthority grantedAuthority : authentication.getAuthorities()) {
+          if (grantedAuthority instanceof AmbariGrantedAuthority) {
 
-          PrivilegeEntity privilegeEntity = ambariGrantedAuthority.getPrivilegeEntity();
-          Integer permissionId = privilegeEntity.getPermission().getId();
+            AmbariGrantedAuthority ambariGrantedAuthority = (AmbariGrantedAuthority) grantedAuthority;
 
-          // admin has full access
-          if (permissionId.equals(PermissionEntity.AMBARI_ADMINISTRATOR_PERMISSION)) {
-            authorized = true;
-            break;
-          }
+            PrivilegeEntity privilegeEntity = ambariGrantedAuthority.getPrivilegeEntity();
+            Integer permissionId = privilegeEntity.getPermission().getId();
 
-          // clusters require permission
-          if (!"GET".equalsIgnoreCase(httpRequest.getMethod()) && requestURI.matches(API_CREDENTIALS_AMBARI_PATTERN)) {
-            // Only the administrator can operate on credentials where the alias starts with "ambari."
+            // admin has full access
             if (permissionId.equals(PermissionEntity.AMBARI_ADMINISTRATOR_PERMISSION)) {
               authorized = true;
               break;
             }
-          } else if (requestURI.matches(API_CLUSTERS_ALL_PATTERN)) {
-            if (permissionId.equals(PermissionEntity.CLUSTER_USER_PERMISSION) ||
-                permissionId.equals(PermissionEntity.CLUSTER_ADMINISTRATOR_PERMISSION)) {
-              authorized = true;
-              break;
-            }
-          } else if (STACK_ADVISOR_REGEX.matcher(requestURI).matches()) {
-            //TODO permissions model doesn't manage stacks api, but we need access to stack advisor to save configs
-            if (permissionId.equals(PermissionEntity.CLUSTER_USER_PERMISSION) ||
-                permissionId.equals(PermissionEntity.CLUSTER_ADMINISTRATOR_PERMISSION)) {
-              authorized = true;
-              break;
-            }
-          } else if (requestURI.matches(API_VIEWS_ALL_PATTERN)) {
-            // views require permission
-            if (permissionId.equals(PermissionEntity.VIEW_USER_PERMISSION)) {
-              authorized = true;
-              break;
+
+            // clusters require permission
+            if (!"GET".equalsIgnoreCase(httpRequest.getMethod()) && requestURI.matches(API_CREDENTIALS_AMBARI_PATTERN)) {
+              // Only the administrator can operate on credentials where the alias starts with "ambari."
+              if (permissionId.equals(PermissionEntity.AMBARI_ADMINISTRATOR_PERMISSION)) {
+                authorized = true;
+                break;
+              }
+            } else if (requestURI.matches(API_CLUSTERS_ALL_PATTERN)) {
+              if (permissionId.equals(PermissionEntity.CLUSTER_USER_PERMISSION) ||
+                  permissionId.equals(PermissionEntity.CLUSTER_ADMINISTRATOR_PERMISSION)) {
+                authorized = true;
+                break;
+              }
+            } else if (STACK_ADVISOR_REGEX.matcher(requestURI).matches()) {
+              //TODO permissions model doesn't manage stacks api, but we need access to stack advisor to save configs
+              if (permissionId.equals(PermissionEntity.CLUSTER_USER_PERMISSION) ||
+                  permissionId.equals(PermissionEntity.CLUSTER_ADMINISTRATOR_PERMISSION)) {
+                authorized = true;
+                break;
+              }
+            } else if (requestURI.matches(API_VIEWS_ALL_PATTERN)) {
+              // views require permission
+              if (permissionId.equals(PermissionEntity.VIEW_USER_PERMISSION)) {
+                authorized = true;
+                break;
+              }
             }
           }
         }
-      }
 
-      // allow GET for everything except /views, /api/v1/users, /api/v1/groups, /api/v1/ldap_sync_events
-      if (!authorized &&
-          (!httpRequest.getMethod().equals("GET")
-              || requestURI.matches(API_LDAP_SYNC_EVENTS_ALL_PATTERN))) {
+        // Allow all GETs that are not LDAP sync events...
+        authorized = authorized || (httpRequest.getMethod().equals("GET") && !requestURI.matches(API_LDAP_SYNC_EVENTS_ALL_PATTERN));
+      }
 
+      if (!authorized) {
         if(auditLogger.isEnabled()) {
           auditEvent = AccessUnauthorizedAuditEvent.builder()
             .withHttpMethodName(httpRequest.getMethod())
@@ -283,6 +294,7 @@ public class AmbariAuthorizationFilter implements Filter {
    */
   private boolean authorizationPerformedInternally(String requestURI) {
     return requestURI.matches(API_USERS_ALL_PATTERN) ||
+        requestURI.matches(API_REQUESTS_ALL_PATTERN) ||
         requestURI.matches(API_GROUPS_ALL_PATTERN) ||
         requestURI.matches(API_CREDENTIALS_ALL_PATTERN) ||
         requestURI.matches(API_PRIVILEGES_ALL_PATTERN) ||
@@ -295,6 +307,7 @@ public class AmbariAuthorizationFilter implements Filter {
         requestURI.matches(VIEWS_CONTEXT_PATH_PATTERN) ||
         requestURI.matches(API_WIDGET_LAYOUTS_PATTERN) ||
         requestURI.matches(API_CLUSTER_HOSTS_ALL_PATTERN) ||
+        requestURI.matches(API_CLUSTER_HOST_COMPONENTS_ALL_PATTERN) ||
         requestURI.matches(API_HOSTS_ALL_PATTERN) ||
         requestURI.matches(API_ALERT_TARGETS_ALL_PATTERN) ||
         requestURI.matches(API_PRIVILEGES_ALL_PATTERN) ||

http://git-wip-us.apache.org/repos/asf/ambari/blob/e7b85260/ambari-server/src/main/java/org/apache/ambari/server/upgrade/UpgradeCatalog240.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/java/org/apache/ambari/server/upgrade/UpgradeCatalog240.java b/ambari-server/src/main/java/org/apache/ambari/server/upgrade/UpgradeCatalog240.java
index ecd8ff1..db6d73a9 100644
--- a/ambari-server/src/main/java/org/apache/ambari/server/upgrade/UpgradeCatalog240.java
+++ b/ambari-server/src/main/java/org/apache/ambari/server/upgrade/UpgradeCatalog240.java
@@ -329,6 +329,7 @@ public class UpgradeCatalog240 extends AbstractUpgradeCatalog {
     setRoleSortOrder();
     addSettingPermission();
     addManageUserPersistedDataPermission();
+    allowClusterOperatorToManageCredentials();
     updateHDFSConfigs();
     updateHIVEConfigs();
     updateAMSConfigs();
@@ -513,6 +514,18 @@ public class UpgradeCatalog240 extends AbstractUpgradeCatalog {
 
   }
 
+  /**
+   * Adds <code>CLUSTER.MANAGE_CREDENTIALS</code> to the set of authorizations a <code>CLUSTER.OPERATOR</code> can perform.
+   *
+   * @throws SQLException
+   */
+  protected void allowClusterOperatorToManageCredentials() throws SQLException {
+    String permissionId = permissionDAO.findPermissionByNameAndType("CLUSTER.OPERATOR",
+        resourceTypeDAO.findByName("CLUSTER")).getId().toString();
+    dbAccessor.insertRowIfMissing("permission_roleauthorization", new String[]{"permission_id", "authorization_id" },
+        new String[]{"'" + permissionId + "'", "'CLUSTER.MANAGE_CREDENTIALS'" }, false);
+  }
+
   protected void removeHiveOozieDBConnectionConfigs() throws AmbariException {
     AmbariManagementController ambariManagementController = injector.getInstance(AmbariManagementController.class);
     Map<String, Cluster> clusterMap = getCheckedClusterMap(ambariManagementController.getClusters());

http://git-wip-us.apache.org/repos/asf/ambari/blob/e7b85260/ambari-server/src/main/resources/Ambari-DDL-Derby-CREATE.sql
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/resources/Ambari-DDL-Derby-CREATE.sql b/ambari-server/src/main/resources/Ambari-DDL-Derby-CREATE.sql
index 2c2d743..e6d1e16 100644
--- a/ambari-server/src/main/resources/Ambari-DDL-Derby-CREATE.sql
+++ b/ambari-server/src/main/resources/Ambari-DDL-Derby-CREATE.sql
@@ -1341,6 +1341,7 @@ INSERT INTO permission_roleauthorization(permission_id, authorization_id)
   SELECT permission_id, 'CLUSTER.VIEW_STACK_DETAILS' FROM adminpermission WHERE permission_name='CLUSTER.OPERATOR'  UNION ALL
   SELECT permission_id, 'CLUSTER.MANAGE_CONFIG_GROUPS' FROM adminpermission WHERE permission_name='CLUSTER.OPERATOR'  UNION ALL
   SELECT permission_id, 'CLUSTER.VIEW_ALERTS' FROM adminpermission WHERE permission_name='CLUSTER.OPERATOR'  UNION ALL
+  SELECT permission_id, 'CLUSTER.MANAGE_CREDENTIALS' FROM adminpermission WHERE permission_name='CLUSTER.OPERATOR'  UNION ALL
   SELECT permission_id, 'CLUSTER.MANAGE_USER_PERSISTED_DATA' FROM adminpermission WHERE permission_name='CLUSTER.OPERATOR';
 
 -- Set authorizations for Cluster Administrator role

http://git-wip-us.apache.org/repos/asf/ambari/blob/e7b85260/ambari-server/src/main/resources/Ambari-DDL-MySQL-CREATE.sql
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/resources/Ambari-DDL-MySQL-CREATE.sql b/ambari-server/src/main/resources/Ambari-DDL-MySQL-CREATE.sql
index ee87cc5..38300b0 100644
--- a/ambari-server/src/main/resources/Ambari-DDL-MySQL-CREATE.sql
+++ b/ambari-server/src/main/resources/Ambari-DDL-MySQL-CREATE.sql
@@ -1274,6 +1274,7 @@ INSERT INTO permission_roleauthorization(permission_id, authorization_id)
   SELECT permission_id, 'CLUSTER.VIEW_STACK_DETAILS' FROM adminpermission WHERE permission_name='CLUSTER.OPERATOR' UNION ALL
   SELECT permission_id, 'CLUSTER.MANAGE_CONFIG_GROUPS' FROM adminpermission WHERE permission_name='CLUSTER.OPERATOR' UNION ALL
   SELECT permission_id, 'CLUSTER.VIEW_ALERTS' FROM adminpermission WHERE permission_name='CLUSTER.OPERATOR' UNION ALL
+  SELECT permission_id, 'CLUSTER.MANAGE_CREDENTIALS' FROM adminpermission WHERE permission_name='CLUSTER.OPERATOR' UNION ALL
   SELECT permission_id, 'CLUSTER.MANAGE_USER_PERSISTED_DATA' FROM adminpermission WHERE permission_name='CLUSTER.OPERATOR';
 
 -- Set authorizations for Cluster Administrator role

http://git-wip-us.apache.org/repos/asf/ambari/blob/e7b85260/ambari-server/src/main/resources/Ambari-DDL-Oracle-CREATE.sql
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/resources/Ambari-DDL-Oracle-CREATE.sql b/ambari-server/src/main/resources/Ambari-DDL-Oracle-CREATE.sql
index edc46f7..a017388 100644
--- a/ambari-server/src/main/resources/Ambari-DDL-Oracle-CREATE.sql
+++ b/ambari-server/src/main/resources/Ambari-DDL-Oracle-CREATE.sql
@@ -1293,6 +1293,7 @@ INSERT INTO permission_roleauthorization(permission_id, authorization_id)
   SELECT permission_id, 'CLUSTER.VIEW_STACK_DETAILS' FROM adminpermission WHERE permission_name='CLUSTER.OPERATOR' UNION ALL
   SELECT permission_id, 'CLUSTER.MANAGE_CONFIG_GROUPS' FROM adminpermission WHERE permission_name='CLUSTER.OPERATOR' UNION ALL
   SELECT permission_id, 'CLUSTER.VIEW_ALERTS' FROM adminpermission WHERE permission_name='CLUSTER.OPERATOR' UNION ALL
+  SELECT permission_id, 'CLUSTER.MANAGE_CREDENTIALS' FROM adminpermission WHERE permission_name='CLUSTER.OPERATOR' UNION ALL
   SELECT permission_id, 'CLUSTER.MANAGE_USER_PERSISTED_DATA' FROM adminpermission WHERE permission_name='CLUSTER.OPERATOR';
 
 -- Set authorizations for Cluster Administrator role

http://git-wip-us.apache.org/repos/asf/ambari/blob/e7b85260/ambari-server/src/main/resources/Ambari-DDL-Postgres-CREATE.sql
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/resources/Ambari-DDL-Postgres-CREATE.sql b/ambari-server/src/main/resources/Ambari-DDL-Postgres-CREATE.sql
index 6f38ec8..7667a6b 100644
--- a/ambari-server/src/main/resources/Ambari-DDL-Postgres-CREATE.sql
+++ b/ambari-server/src/main/resources/Ambari-DDL-Postgres-CREATE.sql
@@ -1265,6 +1265,7 @@ INSERT INTO permission_roleauthorization(permission_id, authorization_id)
   SELECT permission_id, 'CLUSTER.VIEW_STACK_DETAILS' FROM adminpermission WHERE permission_name='CLUSTER.OPERATOR' UNION ALL
   SELECT permission_id, 'CLUSTER.MANAGE_CONFIG_GROUPS' FROM adminpermission WHERE permission_name='CLUSTER.OPERATOR' UNION ALL
   SELECT permission_id, 'CLUSTER.VIEW_ALERTS' FROM adminpermission WHERE permission_name='CLUSTER.OPERATOR' UNION ALL
+  SELECT permission_id, 'CLUSTER.MANAGE_CREDENTIALS' FROM adminpermission WHERE permission_name='CLUSTER.OPERATOR' UNION ALL
   SELECT permission_id, 'CLUSTER.MANAGE_USER_PERSISTED_DATA' FROM adminpermission WHERE permission_name='CLUSTER.OPERATOR';
 
 -- Set authorizations for Cluster Administrator role

http://git-wip-us.apache.org/repos/asf/ambari/blob/e7b85260/ambari-server/src/main/resources/Ambari-DDL-Postgres-EMBEDDED-CREATE.sql
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/resources/Ambari-DDL-Postgres-EMBEDDED-CREATE.sql b/ambari-server/src/main/resources/Ambari-DDL-Postgres-EMBEDDED-CREATE.sql
index ca57de5..9663d56 100644
--- a/ambari-server/src/main/resources/Ambari-DDL-Postgres-EMBEDDED-CREATE.sql
+++ b/ambari-server/src/main/resources/Ambari-DDL-Postgres-EMBEDDED-CREATE.sql
@@ -1427,6 +1427,7 @@ INSERT INTO ambari.permission_roleauthorization(permission_id, authorization_id)
   SELECT permission_id, 'CLUSTER.VIEW_STACK_DETAILS' FROM ambari.adminpermission WHERE permission_name='CLUSTER.OPERATOR' UNION ALL
   SELECT permission_id, 'CLUSTER.MANAGE_CONFIG_GROUPS' FROM ambari.adminpermission WHERE permission_name='CLUSTER.OPERATOR' UNION ALL
   SELECT permission_id, 'CLUSTER.VIEW_ALERTS' FROM ambari.adminpermission WHERE permission_name='CLUSTER.OPERATOR' UNION ALL
+  SELECT permission_id, 'CLUSTER.MANAGE_CREDENTIALS' FROM ambari.adminpermission WHERE permission_name='CLUSTER.OPERATOR' UNION ALL
   SELECT permission_id, 'CLUSTER.MANAGE_USER_PERSISTED_DATA' FROM ambari.adminpermission WHERE permission_name='CLUSTER.OPERATOR';
 
 -- Set authorizations for Cluster Administrator role

http://git-wip-us.apache.org/repos/asf/ambari/blob/e7b85260/ambari-server/src/main/resources/Ambari-DDL-SQLAnywhere-CREATE.sql
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/resources/Ambari-DDL-SQLAnywhere-CREATE.sql b/ambari-server/src/main/resources/Ambari-DDL-SQLAnywhere-CREATE.sql
index 61aadf0..d35dab3 100644
--- a/ambari-server/src/main/resources/Ambari-DDL-SQLAnywhere-CREATE.sql
+++ b/ambari-server/src/main/resources/Ambari-DDL-SQLAnywhere-CREATE.sql
@@ -1290,6 +1290,7 @@ insert into adminpermission(permission_id, permission_name, resource_type_id, pe
     SELECT permission_id, 'CLUSTER.VIEW_STACK_DETAILS' FROM adminpermission WHERE permission_name='CLUSTER.OPERATOR' UNION ALL
     SELECT permission_id, 'CLUSTER.MANAGE_CONFIG_GROUPS' FROM adminpermission WHERE permission_name='CLUSTER.OPERATOR' UNION ALL
     SELECT permission_id, 'CLUSTER.VIEW_ALERTS' FROM adminpermission WHERE permission_name='CLUSTER.OPERATOR' UNION ALL
+    SELECT permission_id, 'CLUSTER.MANAGE_CREDENTIALS' FROM adminpermission WHERE permission_name='CLUSTER.OPERATOR' UNION ALL
     SELECT permission_id, 'CLUSTER.MANAGE_USER_PERSISTED_DATA' FROM adminpermission WHERE permission_name='CLUSTER.OPERATOR';
 
   -- Set authorizations for Cluster Administrator role

http://git-wip-us.apache.org/repos/asf/ambari/blob/e7b85260/ambari-server/src/main/resources/Ambari-DDL-SQLServer-CREATE.sql
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/resources/Ambari-DDL-SQLServer-CREATE.sql b/ambari-server/src/main/resources/Ambari-DDL-SQLServer-CREATE.sql
index 9269b13..23ba2db 100644
--- a/ambari-server/src/main/resources/Ambari-DDL-SQLServer-CREATE.sql
+++ b/ambari-server/src/main/resources/Ambari-DDL-SQLServer-CREATE.sql
@@ -1293,6 +1293,7 @@ BEGIN TRANSACTION
     SELECT permission_id, 'CLUSTER.VIEW_STACK_DETAILS' FROM adminpermission WHERE permission_name='CLUSTER.OPERATOR' UNION ALL
     SELECT permission_id, 'CLUSTER.MANAGE_CONFIG_GROUPS' FROM adminpermission WHERE permission_name='CLUSTER.OPERATOR' UNION ALL
     SELECT permission_id, 'CLUSTER.VIEW_ALERTS' FROM adminpermission WHERE permission_name='CLUSTER.OPERATOR' UNION ALL
+    SELECT permission_id, 'CLUSTER.MANAGE_CREDENTIALS' FROM adminpermission WHERE permission_name='CLUSTER.OPERATOR' UNION ALL
     SELECT permission_id, 'CLUSTER.MANAGE_USER_PERSISTED_DATA' FROM adminpermission WHERE permission_name='CLUSTER.OPERATOR';
 
   -- Set authorizations for Cluster Administrator role

http://git-wip-us.apache.org/repos/asf/ambari/blob/e7b85260/ambari-server/src/main/resources/custom_action_definitions/system_action_definitions.xml
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/resources/custom_action_definitions/system_action_definitions.xml b/ambari-server/src/main/resources/custom_action_definitions/system_action_definitions.xml
index 6304baf..bc1c271 100644
--- a/ambari-server/src/main/resources/custom_action_definitions/system_action_definitions.xml
+++ b/ambari-server/src/main/resources/custom_action_definitions/system_action_definitions.xml
@@ -28,6 +28,7 @@
     <defaultTimeout>60</defaultTimeout>
     <description>General check for host</description>
     <targetType>ANY</targetType>
+    <permissions>HOST.ADD_DELETE_HOSTS</permissions>
   </actionDefinition>
   <actionDefinition>
     <actionName>update_repo</actionName>

http://git-wip-us.apache.org/repos/asf/ambari/blob/e7b85260/ambari-server/src/test/java/org/apache/ambari/server/controller/AmbariManagementControllerTest.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/test/java/org/apache/ambari/server/controller/AmbariManagementControllerTest.java b/ambari-server/src/test/java/org/apache/ambari/server/controller/AmbariManagementControllerTest.java
index 3ec9cb3..42d62c8 100644
--- a/ambari-server/src/test/java/org/apache/ambari/server/controller/AmbariManagementControllerTest.java
+++ b/ambari-server/src/test/java/org/apache/ambari/server/controller/AmbariManagementControllerTest.java
@@ -4314,11 +4314,11 @@ public class AmbariManagementControllerTest {
 
 
     ActionDefinition a1 = new ActionDefinition(actionDef1, ActionType.SYSTEM,
-        "test,[optional1]", "", "", "Does file exist", TargetHostType.SPECIFIC, Short.valueOf("100"));
+        "test,[optional1]", "", "", "Does file exist", TargetHostType.SPECIFIC, Short.valueOf("100"), null);
     controller.getAmbariMetaInfo().addActionDefinition(a1);
     controller.getAmbariMetaInfo().addActionDefinition(new ActionDefinition(
         actionDef2, ActionType.SYSTEM, "", "HDFS", "DATANODE", "Does file exist",
-        TargetHostType.ALL, Short.valueOf("1000")));
+        TargetHostType.ALL, Short.valueOf("1000"), null));
 
     Map<String, String> params = new HashMap<String, String>() {{
       put("test", "test");
@@ -4700,23 +4700,23 @@ public class AmbariManagementControllerTest {
 
     controller.getAmbariMetaInfo().addActionDefinition(new ActionDefinition(
         actionDef1, ActionType.SYSTEM, "test,dirName", "", "", "Does file exist",
-        TargetHostType.SPECIFIC, Short.valueOf("100")));
+        TargetHostType.SPECIFIC, Short.valueOf("100"), null));
 
     controller.getAmbariMetaInfo().addActionDefinition(new ActionDefinition(
         actionDef2, ActionType.SYSTEM, "", "HDFS", "DATANODE", "Does file exist",
-        TargetHostType.ANY, Short.valueOf("100")));
+        TargetHostType.ANY, Short.valueOf("100"), null));
 
     controller.getAmbariMetaInfo().addActionDefinition(new ActionDefinition(
             "update_repo", ActionType.SYSTEM, "", "HDFS", "DATANODE", "Does file exist",
-            TargetHostType.ANY, Short.valueOf("100")));
+            TargetHostType.ANY, Short.valueOf("100"), null));
 
     controller.getAmbariMetaInfo().addActionDefinition(new ActionDefinition(
         actionDef3, ActionType.SYSTEM, "", "MAPREDUCE", "MAPREDUCE_CLIENT", "Does file exist",
-        TargetHostType.ANY, Short.valueOf("100")));
+        TargetHostType.ANY, Short.valueOf("100"), null));
 
     controller.getAmbariMetaInfo().addActionDefinition(new ActionDefinition(
         actionDef4, ActionType.SYSTEM, "", "HIVE", "", "Does file exist",
-        TargetHostType.ANY, Short.valueOf("100")));
+        TargetHostType.ANY, Short.valueOf("100"), null));
 
     actionRequest = new ExecuteActionRequest(cluster1, null, actionDef1, null, null, null, false);
     expectActionCreationErrorWithMessage(actionRequest, requestProperties,
@@ -6560,7 +6560,7 @@ public class AmbariManagementControllerTest {
 
     controller.getAmbariMetaInfo().addActionDefinition(new ActionDefinition(
       action1, ActionType.SYSTEM, "", "HDFS", "", "Some custom action.",
-      TargetHostType.ALL, Short.valueOf("10010")));
+      TargetHostType.ALL, Short.valueOf("10010"), null));
 
     Map<String, String> params = new HashMap<String, String>() {{
       put("test", "test");
@@ -10601,7 +10601,7 @@ public class AmbariManagementControllerTest {
 
     ambariMetaInfo.addActionDefinition(new ActionDefinition(action1, ActionType.SYSTEM,
         "", "", "", "action def description", TargetHostType.ANY,
-        Short.valueOf("60")));
+        Short.valueOf("60"), null));
 
     Map<String, String> requestProperties = new HashMap<String, String>();
     requestProperties.put(REQUEST_CONTEXT_PROPERTY, "Called from a test");

http://git-wip-us.apache.org/repos/asf/ambari/blob/e7b85260/ambari-server/src/test/java/org/apache/ambari/server/controller/internal/ActionResourceProviderTest.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/test/java/org/apache/ambari/server/controller/internal/ActionResourceProviderTest.java b/ambari-server/src/test/java/org/apache/ambari/server/controller/internal/ActionResourceProviderTest.java
index 96995b4..c581ff4 100644
--- a/ambari-server/src/test/java/org/apache/ambari/server/controller/internal/ActionResourceProviderTest.java
+++ b/ambari-server/src/test/java/org/apache/ambari/server/controller/internal/ActionResourceProviderTest.java
@@ -97,13 +97,13 @@ public class ActionResourceProviderTest {
     List<ActionDefinition> allDefinition = new ArrayList<ActionDefinition>();
     allDefinition.add(new ActionDefinition(
         "a1", ActionType.SYSTEM, "fileName", "HDFS", "DATANODE", "Does file exist", TargetHostType.ANY,
-        Short.valueOf("100")));
+        Short.valueOf("100"), null));
     allDefinition.add(new ActionDefinition(
         "a2", ActionType.SYSTEM, "fileName", "HDFS", "DATANODE", "Does file exist", TargetHostType.ANY,
-        Short.valueOf("100")));
+        Short.valueOf("100"), null));
     allDefinition.add(new ActionDefinition(
         "a3", ActionType.SYSTEM, "fileName", "HDFS", "DATANODE", "Does file exist", TargetHostType.ANY,
-        Short.valueOf("100")));
+        Short.valueOf("100"), null));
 
     Set<ActionResponse> allResponse = new HashSet<ActionResponse>();
     for (ActionDefinition definition : allDefinition) {
@@ -112,7 +112,7 @@ public class ActionResourceProviderTest {
 
     ActionDefinition namedDefinition = new ActionDefinition(
         "a1", ActionType.SYSTEM, "fileName", "HDFS", "DATANODE", "Does file exist", TargetHostType.ANY,
-        Short.valueOf("100"));
+        Short.valueOf("100"), null);
 
     Set<ActionResponse> nameResponse = new HashSet<ActionResponse>();
     nameResponse.add(namedDefinition.convertToResponse());

http://git-wip-us.apache.org/repos/asf/ambari/blob/e7b85260/ambari-server/src/test/java/org/apache/ambari/server/controller/internal/RequestResourceProviderTest.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/test/java/org/apache/ambari/server/controller/internal/RequestResourceProviderTest.java b/ambari-server/src/test/java/org/apache/ambari/server/controller/internal/RequestResourceProviderTest.java
index 65efc63..4444714 100644
--- a/ambari-server/src/test/java/org/apache/ambari/server/controller/internal/RequestResourceProviderTest.java
+++ b/ambari-server/src/test/java/org/apache/ambari/server/controller/internal/RequestResourceProviderTest.java
@@ -22,19 +22,20 @@ package org.apache.ambari.server.controller.internal;
 import static org.apache.ambari.server.controller.internal.HostComponentResourceProvider.HOST_COMPONENT_STALE_CONFIGS_PROPERTY_ID;
 import static org.easymock.EasyMock.anyObject;
 import static org.easymock.EasyMock.capture;
-import static org.easymock.EasyMock.createMock;
-import static org.easymock.EasyMock.createNiceMock;
-import static org.easymock.EasyMock.eq;
 import static org.easymock.EasyMock.expect;
+import static org.easymock.EasyMock.eq;
 import static org.easymock.EasyMock.newCapture;
-import static org.easymock.EasyMock.replay;
-import static org.easymock.EasyMock.reset;
-import static org.easymock.EasyMock.verify;
+import static org.powermock.api.easymock.PowerMock.createMock;
+import static org.powermock.api.easymock.PowerMock.createNiceMock;
+import static org.powermock.api.easymock.PowerMock.replay;
+import static org.powermock.api.easymock.PowerMock.reset;
+import static org.powermock.api.easymock.PowerMock.verify;
 
 import java.lang.reflect.Field;
 import java.util.Arrays;
 import java.util.Collection;
 import java.util.Collections;
+import java.util.EnumSet;
 import java.util.HashMap;
 import java.util.HashSet;
 import java.util.LinkedHashMap;
@@ -49,6 +50,7 @@ import org.apache.ambari.server.actionmanager.ActionManager;
 import org.apache.ambari.server.actionmanager.HostRoleCommand;
 import org.apache.ambari.server.actionmanager.HostRoleStatus;
 import org.apache.ambari.server.actionmanager.Stage;
+import org.apache.ambari.server.api.services.AmbariMetaInfo;
 import org.apache.ambari.server.api.services.BaseRequest;
 import org.apache.ambari.server.controller.AmbariManagementController;
 import org.apache.ambari.server.controller.AmbariServer;
@@ -63,6 +65,7 @@ import org.apache.ambari.server.controller.utilities.ClusterControllerHelper;
 import org.apache.ambari.server.controller.utilities.PredicateBuilder;
 import org.apache.ambari.server.controller.utilities.PredicateHelper;
 import org.apache.ambari.server.controller.utilities.PropertyHelper;
+import org.apache.ambari.server.customactions.ActionDefinition;
 import org.apache.ambari.server.orm.dao.HostRoleCommandDAO;
 import org.apache.ambari.server.orm.dao.HostRoleCommandStatusSummaryDTO;
 import org.apache.ambari.server.orm.dao.RequestDAO;
@@ -70,6 +73,7 @@ import org.apache.ambari.server.orm.entities.RequestEntity;
 import org.apache.ambari.server.security.TestAuthenticationFactory;
 import org.apache.ambari.server.security.authorization.AuthorizationException;
 import org.apache.ambari.server.security.authorization.AuthorizationHelperInitializer;
+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.topology.ClusterTopology;
@@ -1307,21 +1311,69 @@ public class RequestResourceProviderTest {
   }
 
   @Test
-  public void testCreateResourcesForNonCluster() throws Exception {
+  public void testCreateResourcesCheckHostForNonClusterAsAdministrator() throws Exception {
+    testCreateResourcesForNonCluster(TestAuthenticationFactory.createAdministrator(), "check_host",
+        EnumSet.of(RoleAuthorization.HOST_ADD_DELETE_HOSTS));
+  }
+
+  @Test
+  public void testCreateResourcesCheckHostForNonClusterAsClusterAdministrator() throws Exception {
+    testCreateResourcesForNonCluster(TestAuthenticationFactory.createClusterAdministrator(), "check_host",
+        EnumSet.of(RoleAuthorization.HOST_ADD_DELETE_HOSTS));
+  }
+
+  @Test
+  public void testCreateResourcesCheckHostForNonClusterAsClusterOperator() throws Exception {
+    testCreateResourcesForNonCluster(TestAuthenticationFactory.createClusterOperator(), "check_host",
+        EnumSet.of(RoleAuthorization.HOST_ADD_DELETE_HOSTS));
+  }
+
+  @Test(expected = AuthorizationException.class)
+  public void testCreateResourcesCheckHostForNonClusterAsServiceAdministrator() throws Exception {
+    testCreateResourcesForNonCluster(TestAuthenticationFactory.createServiceAdministrator(), "check_host",
+        EnumSet.of(RoleAuthorization.HOST_ADD_DELETE_HOSTS));
+  }
+
+  @Test
+  public void testCreateResourcesCheckJavaForNonClusterAsAdministrator() throws Exception {
+    testCreateResourcesForNonCluster(TestAuthenticationFactory.createAdministrator(), "check_java", null);
+  }
+
+  @Test(expected = AuthorizationException.class)
+  public void testCreateResourcesCheckJavaForNonClusterAsClusterAdministrator() throws Exception {
+    testCreateResourcesForNonCluster(TestAuthenticationFactory.createClusterAdministrator(), "check_java", null);
+  }
+
+  @Test(expected = AuthorizationException.class)
+  public void testCreateResourcesCheckJavaForNonClusterAsClusterOperator() throws Exception {
+    testCreateResourcesForNonCluster(TestAuthenticationFactory.createClusterOperator(), "check_java", null);
+  }
+
+  @Test(expected = AuthorizationException.class)
+  public void testCreateResourcesForNonClusterAsServiceAdministrator() throws Exception {
+    testCreateResourcesForNonCluster(TestAuthenticationFactory.createServiceAdministrator(), "check_java", null);
+  }
+
+  private void testCreateResourcesForNonCluster(Authentication authentication, String actionName, Set<RoleAuthorization> permissions) throws Exception {
     Resource.Type type = Resource.Type.Request;
 
     Capture<ExecuteActionRequest> actionRequest = newCapture();
     Capture<HashMap<String, String>> propertyMap = newCapture();
 
     AmbariManagementController managementController = createMock(AmbariManagementController.class);
+    AmbariMetaInfo metaInfo = createMock(AmbariMetaInfo.class);
+    ActionDefinition actionDefinition = createMock(ActionDefinition.class);
     RequestStatusResponse response = createNiceMock(RequestStatusResponse.class);
 
     expect(managementController.createAction(capture(actionRequest), capture(propertyMap)))
       .andReturn(response).anyTimes();
+    expect(managementController.getAmbariMetaInfo()).andReturn(metaInfo).anyTimes();
+    expect(metaInfo.getActionDefinition(actionName)).andReturn(actionDefinition).anyTimes();
+    expect(actionDefinition.getPermissions()).andReturn(permissions).anyTimes();
     expect(response.getMessage()).andReturn("Message").anyTimes();
 
     // replay
-    replay(managementController, response);
+    replay(managementController, metaInfo, actionDefinition, response);
 
     // add the property map to a set for the request.  add more maps for multiple creates
     Set<Map<String, Object>> propertySet = new LinkedHashSet<Map<String, Object>>();
@@ -1338,7 +1390,9 @@ public class RequestResourceProviderTest {
     propertySet.add(properties);
 
     Map<String, String> requestInfoProperties = new HashMap<String, String>();
-    requestInfoProperties.put(RequestResourceProvider.ACTION_ID, "check_java");
+    requestInfoProperties.put(RequestResourceProvider.ACTION_ID, actionName);
+
+    SecurityContextHolder.getContext().setAuthentication(authentication);
 
     // create the request
     Request request = PropertyHelper.getCreateRequest(propertySet, requestInfoProperties);
@@ -1352,7 +1406,7 @@ public class RequestResourceProviderTest {
 
     Assert.assertTrue(actionRequest.hasCaptured());
     Assert.assertFalse("expected an action", capturedRequest.isCommand());
-    Assert.assertEquals("check_java", capturedRequest.getActionName());
+    Assert.assertEquals(actionName, capturedRequest.getActionName());
     Assert.assertEquals(null, capturedRequest.getCommandName());
     Assert.assertNotNull(capturedRequest.getResourceFilters());
     Assert.assertEquals(1, capturedRequest.getResourceFilters().size());

http://git-wip-us.apache.org/repos/asf/ambari/blob/e7b85260/ambari-server/src/test/java/org/apache/ambari/server/customactions/ActionDefinitionManagerTest.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/test/java/org/apache/ambari/server/customactions/ActionDefinitionManagerTest.java b/ambari-server/src/test/java/org/apache/ambari/server/customactions/ActionDefinitionManagerTest.java
index ec84922..f7808d1 100644
--- a/ambari-server/src/test/java/org/apache/ambari/server/customactions/ActionDefinitionManagerTest.java
+++ b/ambari-server/src/test/java/org/apache/ambari/server/customactions/ActionDefinitionManagerTest.java
@@ -19,22 +19,25 @@
 package org.apache.ambari.server.customactions;
 
 import java.io.File;
+import java.util.EnumSet;
 
 import junit.framework.Assert;
 import org.apache.ambari.server.actionmanager.ActionType;
 import org.apache.ambari.server.actionmanager.TargetHostType;
+import org.apache.ambari.server.security.authorization.RoleAuthorization;
 import org.junit.Test;
 
 public class ActionDefinitionManagerTest {
 
-  private final String customActionDefinitionRoot = "./src/test/resources/custom_action_definitions/";
+  private static final String CUSTOM_ACTION_DEFINITION_ROOT = "./src/test/resources/custom_action_definitions/";
+  private static final String CUSTOM_ACTION_DEFINITION_INVALID_ROOT = "./src/test/resources/custom_action_definitions_invalid/";
 
   @Test
   public void testReadCustomActionDefinitions() throws Exception {
     ActionDefinitionManager manager = new ActionDefinitionManager();
-    manager.readCustomActionDefinitions(new File(customActionDefinitionRoot));
+    manager.readCustomActionDefinitions(new File(CUSTOM_ACTION_DEFINITION_ROOT));
 
-    Assert.assertEquals(2, manager.getAllActionDefinition().size());
+    Assert.assertEquals(3, manager.getAllActionDefinition().size());
     ActionDefinition ad = manager.getActionDefinition("customAction1");
     Assert.assertNotNull(ad);
     Assert.assertEquals("customAction1", ad.getActionName());
@@ -45,6 +48,7 @@ public class ActionDefinitionManagerTest {
     Assert.assertEquals(60, (int)ad.getDefaultTimeout());
     Assert.assertEquals(TargetHostType.ALL, ad.getTargetType());
     Assert.assertEquals(ActionType.USER, ad.getActionType());
+    Assert.assertEquals(EnumSet.of(RoleAuthorization.HOST_ADD_DELETE_COMPONENTS, RoleAuthorization.HOST_ADD_DELETE_HOSTS), ad.getPermissions());
 
     ad = manager.getActionDefinition("customAction2");
     Assert.assertNotNull(ad);
@@ -56,6 +60,25 @@ public class ActionDefinitionManagerTest {
     Assert.assertEquals(60, (int)ad.getDefaultTimeout());
     Assert.assertEquals(null, ad.getTargetType());
     Assert.assertEquals(ActionType.USER, ad.getActionType());
+    Assert.assertEquals(EnumSet.of(RoleAuthorization.HOST_ADD_DELETE_COMPONENTS, RoleAuthorization.HOST_ADD_DELETE_HOSTS), ad.getPermissions());
+
+    ad = manager.getActionDefinition("customAction3");
+    Assert.assertNotNull(ad);
+    Assert.assertEquals("customAction3", ad.getActionName());
+    Assert.assertEquals("A random test", ad.getDescription());
+    Assert.assertEquals(null, ad.getInputs());
+    Assert.assertEquals("TASKTRACKER", ad.getTargetComponent());
+    Assert.assertEquals("MAPREDUCE", ad.getTargetService());
+    Assert.assertEquals(60, (int)ad.getDefaultTimeout());
+    Assert.assertEquals(null, ad.getTargetType());
+    Assert.assertEquals(ActionType.USER, ad.getActionType());
+    Assert.assertNull(ad.getPermissions());
+  }
+
+  @Test(expected = IllegalArgumentException.class)
+  public void testReadInvalidCustomActionDefinitions() throws Exception {
+    ActionDefinitionManager manager = new ActionDefinitionManager();
+    manager.readCustomActionDefinitions(new File(CUSTOM_ACTION_DEFINITION_INVALID_ROOT));
   }
 }
 

http://git-wip-us.apache.org/repos/asf/ambari/blob/e7b85260/ambari-server/src/test/java/org/apache/ambari/server/security/TestAuthenticationFactory.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/test/java/org/apache/ambari/server/security/TestAuthenticationFactory.java b/ambari-server/src/test/java/org/apache/ambari/server/security/TestAuthenticationFactory.java
index 69b4b08..4301bf8 100644
--- a/ambari-server/src/test/java/org/apache/ambari/server/security/TestAuthenticationFactory.java
+++ b/ambari-server/src/test/java/org/apache/ambari/server/security/TestAuthenticationFactory.java
@@ -48,10 +48,18 @@ public class TestAuthenticationFactory {
     return createClusterAdministrator("clusterAdmin", 4L);
   }
 
+  public static Authentication createClusterOperator() {
+    return createClusterOperator("clusterOp", 4L);
+  }
+
   public static Authentication createClusterAdministrator(String name, Long clusterResourceId) {
     return new TestAuthorization(name, Collections.singleton(createClusterAdministratorGrantedAuthority(clusterResourceId)));
   }
 
+  public static Authentication createClusterOperator(String name, Long clusterResourceId) {
+    return new TestAuthorization(name, Collections.singleton(createClusterOperatorGrantedAuthority(clusterResourceId)));
+  }
+
   public static Authentication createServiceAdministrator() {
     return createServiceAdministrator("serviceAdmin", 4L);
   }
@@ -92,6 +100,10 @@ public class TestAuthenticationFactory {
     return new AmbariGrantedAuthority(createClusterAdministratorPrivilegeEntity(clusterResourceId));
   }
 
+  private static GrantedAuthority createClusterOperatorGrantedAuthority(Long clusterResourceId) {
+    return new AmbariGrantedAuthority(createClusterOperatorPrivilegeEntity(clusterResourceId));
+  }
+
   private static GrantedAuthority createServiceAdministratorGrantedAuthority(Long clusterResourceId) {
     return new AmbariGrantedAuthority(createServiceAdministratorPrivilegeEntity(clusterResourceId));
   }
@@ -122,6 +134,13 @@ public class TestAuthenticationFactory {
     return privilegeEntity;
   }
 
+  private static PrivilegeEntity createClusterOperatorPrivilegeEntity(Long clusterResourceId) {
+    PrivilegeEntity privilegeEntity = new PrivilegeEntity();
+    privilegeEntity.setResource(createClusterResourceEntity(clusterResourceId));
+    privilegeEntity.setPermission(createClusterOperatorPermission());
+    return privilegeEntity;
+  }
+
   private static PrivilegeEntity createServiceAdministratorPrivilegeEntity(Long clusterResourceId) {
     PrivilegeEntity privilegeEntity = new PrivilegeEntity();
     privilegeEntity.setResource(createClusterResourceEntity(clusterResourceId));
@@ -200,6 +219,44 @@ public class TestAuthenticationFactory {
     return permissionEntity;
   }
 
+  private static PermissionEntity createClusterOperatorPermission() {
+    PermissionEntity permissionEntity = new PermissionEntity();
+    permissionEntity.setId(5);
+    permissionEntity.setResourceType(createResourceTypeEntity(ResourceType.CLUSTER));
+    permissionEntity.setAuthorizations(createAuthorizations(EnumSet.of(
+        RoleAuthorization.HOST_VIEW_CONFIGS,
+        RoleAuthorization.HOST_ADD_DELETE_COMPONENTS,
+        RoleAuthorization.HOST_VIEW_METRICS,
+        RoleAuthorization.SERVICE_DECOMMISSION_RECOMMISSION,
+        RoleAuthorization.CLUSTER_VIEW_CONFIGS,
+        RoleAuthorization.SERVICE_MANAGE_ALERTS,
+        RoleAuthorization.SERVICE_ENABLE_HA,
+        RoleAuthorization.SERVICE_VIEW_METRICS,
+        RoleAuthorization.SERVICE_RUN_CUSTOM_COMMAND,
+        RoleAuthorization.HOST_VIEW_STATUS_INFO,
+        RoleAuthorization.CLUSTER_VIEW_METRICS,
+        RoleAuthorization.SERVICE_VIEW_STATUS_INFO,
+        RoleAuthorization.CLUSTER_VIEW_STACK_DETAILS,
+        RoleAuthorization.SERVICE_COMPARE_CONFIGS,
+        RoleAuthorization.SERVICE_VIEW_ALERTS,
+        RoleAuthorization.CLUSTER_MANAGE_CONFIG_GROUPS,
+        RoleAuthorization.SERVICE_TOGGLE_ALERTS,
+        RoleAuthorization.SERVICE_MOVE,
+        RoleAuthorization.SERVICE_RUN_SERVICE_CHECK,
+        RoleAuthorization.SERVICE_MODIFY_CONFIGS,
+        RoleAuthorization.CLUSTER_VIEW_STATUS_INFO,
+        RoleAuthorization.SERVICE_VIEW_CONFIGS,
+        RoleAuthorization.HOST_ADD_DELETE_HOSTS,
+        RoleAuthorization.SERVICE_START_STOP,
+        RoleAuthorization.CLUSTER_VIEW_ALERTS,
+        RoleAuthorization.HOST_TOGGLE_MAINTENANCE,
+        RoleAuthorization.SERVICE_TOGGLE_MAINTENANCE,
+        RoleAuthorization.SERVICE_MANAGE_CONFIG_GROUPS,
+        RoleAuthorization.CLUSTER_MANAGE_USER_PERSISTED_DATA,
+        RoleAuthorization.CLUSTER_MANAGE_CREDENTIALS)));
+    return permissionEntity;
+  }
+
   private static PermissionEntity createServiceAdministratorPermission() {
     PermissionEntity permissionEntity = new PermissionEntity();
     permissionEntity.setId(5);

http://git-wip-us.apache.org/repos/asf/ambari/blob/e7b85260/ambari-server/src/test/java/org/apache/ambari/server/upgrade/UpgradeCatalog240Test.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/test/java/org/apache/ambari/server/upgrade/UpgradeCatalog240Test.java b/ambari-server/src/test/java/org/apache/ambari/server/upgrade/UpgradeCatalog240Test.java
index 4dedc98..2490851 100644
--- a/ambari-server/src/test/java/org/apache/ambari/server/upgrade/UpgradeCatalog240Test.java
+++ b/ambari-server/src/test/java/org/apache/ambari/server/upgrade/UpgradeCatalog240Test.java
@@ -464,6 +464,7 @@ public class UpgradeCatalog240Test {
     Method addNewConfigurationsFromXml = AbstractUpgradeCatalog.class.getDeclaredMethod("addNewConfigurationsFromXml");
     Method updateAlerts = UpgradeCatalog240.class.getDeclaredMethod("updateAlerts");
     Method addManageUserPersistedDataPermission = UpgradeCatalog240.class.getDeclaredMethod("addManageUserPersistedDataPermission");
+    Method allowClusterOperatorToManageCredentials = UpgradeCatalog240.class.getDeclaredMethod("allowClusterOperatorToManageCredentials");
     Method addSettingPermission = UpgradeCatalog240.class.getDeclaredMethod("addSettingPermission");
     Method updateHDFSConfigs = UpgradeCatalog240.class.getDeclaredMethod("updateHDFSConfigs");
     Method updateHIVEConfigs = UpgradeCatalog240.class.getDeclaredMethod("updateHIVEConfigs");
@@ -495,6 +496,7 @@ public class UpgradeCatalog240Test {
             .addMockedMethod(updateAlerts)
             .addMockedMethod(addSettingPermission)
             .addMockedMethod(addManageUserPersistedDataPermission)
+            .addMockedMethod(allowClusterOperatorToManageCredentials)
             .addMockedMethod(updateHDFSConfigs)
             .addMockedMethod(updateHIVEConfigs)
             .addMockedMethod(updateAmsConfigs)
@@ -520,6 +522,7 @@ public class UpgradeCatalog240Test {
     upgradeCatalog240.updateAlerts();
     upgradeCatalog240.addSettingPermission();
     upgradeCatalog240.addManageUserPersistedDataPermission();
+    upgradeCatalog240.allowClusterOperatorToManageCredentials();
     upgradeCatalog240.updateHDFSConfigs();
     upgradeCatalog240.updateHIVEConfigs();
     upgradeCatalog240.updateAMSConfigs();

http://git-wip-us.apache.org/repos/asf/ambari/blob/e7b85260/ambari-server/src/test/resources/custom_action_definitions/cust_action_definitions1.xml
----------------------------------------------------------------------
diff --git a/ambari-server/src/test/resources/custom_action_definitions/cust_action_definitions1.xml b/ambari-server/src/test/resources/custom_action_definitions/cust_action_definitions1.xml
index 9cee575..e8e6bc8 100644
--- a/ambari-server/src/test/resources/custom_action_definitions/cust_action_definitions1.xml
+++ b/ambari-server/src/test/resources/custom_action_definitions/cust_action_definitions1.xml
@@ -27,6 +27,7 @@
     <targetComponent>TASKTRACKER</targetComponent>
     <description>A random test</description>
     <targetType>ALL</targetType>
+    <permissions>HOST.ADD_DELETE_HOSTS,HOST.ADD_DELETE_COMPONENTS</permissions>
   </actionDefinition>
   <actionDefinition>
     <actionName>customAction2</actionName>
@@ -34,9 +35,17 @@
     <targetService>MAPREDUCE</targetService>
     <targetComponent>TASKTRACKER</targetComponent>
     <description>A random test</description>
+    <permissions> HOST.ADD_DELETE_HOSTS , HOST.ADD_DELETE_COMPONENTS </permissions> <!-- Note the spaces -->
   </actionDefinition>
   <actionDefinition>
     <actionName>customAction3</actionName>
+    <actionType>USER</actionType>
+    <targetService>MAPREDUCE</targetService>
+    <targetComponent>TASKTRACKER</targetComponent>
+    <description>A random test</description>
+  </actionDefinition>
+  <actionDefinition>
+    <actionName>customAction4</actionName>
     <actionType>USERS_OWN</actionType>
     <targetService>MAPREDUCE</targetService>
     <targetComponent>TASKTRACKER</targetComponent>

http://git-wip-us.apache.org/repos/asf/ambari/blob/e7b85260/ambari-server/src/test/resources/custom_action_definitions_invalid/cust_action_definitions_invalid.xml
----------------------------------------------------------------------
diff --git a/ambari-server/src/test/resources/custom_action_definitions_invalid/cust_action_definitions_invalid.xml b/ambari-server/src/test/resources/custom_action_definitions_invalid/cust_action_definitions_invalid.xml
new file mode 100644
index 0000000..a6fd71e
--- /dev/null
+++ b/ambari-server/src/test/resources/custom_action_definitions_invalid/cust_action_definitions_invalid.xml
@@ -0,0 +1,33 @@
+<?xml version="1.0"?>
+<?xml-stylesheet type="text/xsl" href="action_definition.xsl"?>
+
+<!--
+  ~ 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.
+  -->
+
+<actionDefinitions>
+  <actionDefinition>
+    <actionName>invalidCustomAction1</actionName>
+    <actionType>USER</actionType>
+    <inputs>threshold</inputs>
+    <targetService>MAPREDUCE</targetService>
+    <targetComponent>TASKTRACKER</targetComponent>
+    <description>A random test</description>
+    <targetType>ALL</targetType>
+    <permissions>NOT.A.PERMISSION</permissions>
+  </actionDefinition>
+</actionDefinitions>
\ No newline at end of file


Mime
View raw message