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/87b0a243
Tree: http://git-wip-us.apache.org/repos/asf/ambari/tree/87b0a243
Diff: http://git-wip-us.apache.org/repos/asf/ambari/diff/87b0a243

Branch: refs/heads/trunk
Commit: 87b0a24384fc592bd1c54b50e7095e849a6fc3a2
Parents: 1529af0
Author: Robert Levas <[email protected]>
Authored: Fri May 27 13:46:43 2016 -0400
Committer: Robert Levas <[email protected]>
Committed: Fri May 27 13:46:43 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/87b0a243/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/87b0a243/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/87b0a243/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/87b0a243/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/87b0a243/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/87b0a243/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 0deba5d..dbbf477 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/87b0a243/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/87b0a243/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/87b0a243/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/87b0a243/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/87b0a243/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/87b0a243/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/87b0a243/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/87b0a243/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/87b0a243/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/87b0a243/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/87b0a243/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/87b0a243/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/87b0a243/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/87b0a243/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/87b0a243/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/87b0a243/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

Reply via email to