Repository: ambari Updated Branches: refs/heads/trunk 7ee9fa875 -> ae6dbcea6
AMBARI-15190. Authorization for Auto start services (rlevas) Project: http://git-wip-us.apache.org/repos/asf/ambari/repo Commit: http://git-wip-us.apache.org/repos/asf/ambari/commit/ae6dbcea Tree: http://git-wip-us.apache.org/repos/asf/ambari/tree/ae6dbcea Diff: http://git-wip-us.apache.org/repos/asf/ambari/diff/ae6dbcea Branch: refs/heads/trunk Commit: ae6dbcea63d5fe8b691723e0c86d80480719aefd Parents: 7ee9fa8 Author: Robert Levas <[email protected]> Authored: Mon Feb 29 10:27:58 2016 -0500 Committer: Robert Levas <[email protected]> Committed: Mon Feb 29 10:28:03 2016 -0500 ---------------------------------------------------------------------- .../internal/ComponentResourceProvider.java | 4 + .../internal/ComponentResourceProviderTest.java | 130 +++++++++++++++++++ ambari-web/app/views/main/admin.js | 2 +- ambari-web/app/views/main/menu.js | 4 +- 4 files changed, 137 insertions(+), 3 deletions(-) ---------------------------------------------------------------------- http://git-wip-us.apache.org/repos/asf/ambari/blob/ae6dbcea/ambari-server/src/main/java/org/apache/ambari/server/controller/internal/ComponentResourceProvider.java ---------------------------------------------------------------------- diff --git a/ambari-server/src/main/java/org/apache/ambari/server/controller/internal/ComponentResourceProvider.java b/ambari-server/src/main/java/org/apache/ambari/server/controller/internal/ComponentResourceProvider.java index 03d74a7..6236ac2 100644 --- a/ambari-server/src/main/java/org/apache/ambari/server/controller/internal/ComponentResourceProvider.java +++ b/ambari-server/src/main/java/org/apache/ambari/server/controller/internal/ComponentResourceProvider.java @@ -542,6 +542,10 @@ public class ComponentResourceProvider extends AbstractControllerResourceProvide // Gather the components affected by the change in // auto start state if (!StringUtils.isEmpty(request.getRecoveryEnabled())) { + // Verify that the authenticated user has authorization to change auto-start states for services + AuthorizationHelper.verifyAuthorization(ResourceType.CLUSTER, getClusterResourceId(clusterName), + EnumSet.of(RoleAuthorization.SERVICE_START_STOP)); + boolean newRecoveryEnabled = Boolean.parseBoolean(request.getRecoveryEnabled()); boolean oldRecoveryEnabled = sc.isRecoveryEnabled(); if (newRecoveryEnabled != oldRecoveryEnabled) { http://git-wip-us.apache.org/repos/asf/ambari/blob/ae6dbcea/ambari-server/src/test/java/org/apache/ambari/server/controller/internal/ComponentResourceProviderTest.java ---------------------------------------------------------------------- diff --git a/ambari-server/src/test/java/org/apache/ambari/server/controller/internal/ComponentResourceProviderTest.java b/ambari-server/src/test/java/org/apache/ambari/server/controller/internal/ComponentResourceProviderTest.java index 042c5d4..286b3cf 100644 --- a/ambari-server/src/test/java/org/apache/ambari/server/controller/internal/ComponentResourceProviderTest.java +++ b/ambari-server/src/test/java/org/apache/ambari/server/controller/internal/ComponentResourceProviderTest.java @@ -604,6 +604,136 @@ public class ComponentResourceProviderTest { verify(managementController); } + @Test + public void testUpdateAutoStartAsAdministrator() throws Exception { + testUpdateAutoStart(TestAuthenticationFactory.createAdministrator()); + } + + @Test + public void testUpdateAutoStartAsClusterAdministrator() throws Exception { + testUpdateAutoStart(TestAuthenticationFactory.createClusterAdministrator()); + } + + @Test + public void testUpdateAutoStartAsServiceAdministrator() throws Exception { + testUpdateAutoStart(TestAuthenticationFactory.createServiceAdministrator()); + } + + @Test(expected = AuthorizationException.class) + public void testUpdateAutoStartAsClusterUser() throws Exception { + testUpdateAutoStart(TestAuthenticationFactory.createClusterUser()); + } + + /** + * Perform steps to test updating the Auto-Start property (ServiceComponentInfo/recovery_enabled) + * of a service. + * + * @param authentication the authentication and authorization details of the acting user + * @throws Exception + */ + private void testUpdateAutoStart(Authentication authentication) throws Exception { + Resource.Type type = Resource.Type.Component; + + MaintenanceStateHelper maintenanceStateHelper = createMock(MaintenanceStateHelper.class); + AmbariManagementController managementController = createMock(AmbariManagementController.class); + Clusters clusters = createMock(Clusters.class); + Cluster cluster = createMock(Cluster.class); + AmbariMetaInfo ambariMetaInfo = createMock(AmbariMetaInfo.class); + Service service = createMock(Service.class); + ComponentInfo component1Info = createMock(ComponentInfo.class); + + ServiceComponent serviceComponent1 = createMock(ServiceComponent.class); + ServiceComponentHost serviceComponentHost = createMock(ServiceComponentHost.class); + RequestStatusResponse requestStatusResponse = createNiceMock(RequestStatusResponse.class); + StackId stackId = createMock(StackId.class); + + Map<String, ServiceComponent> serviceComponentMap = new HashMap<String, ServiceComponent>(); + serviceComponentMap.put("Component101", serviceComponent1); + + // set expectations + expect(managementController.getClusters()).andReturn(clusters).anyTimes(); + expect(managementController.getAmbariMetaInfo()).andReturn(ambariMetaInfo).anyTimes(); + expect(managementController.getEffectiveMaintenanceState( + capture(EasyMock.<ServiceComponentHost>newCapture()))).andReturn(MaintenanceState.OFF).anyTimes(); + + expect(stackId.getStackName()).andReturn("stackName").anyTimes(); + expect(stackId.getStackVersion()).andReturn("1").anyTimes(); + + expect(clusters.getCluster("Cluster100")).andReturn(cluster).anyTimes(); + + expect(cluster.getDesiredStackVersion()).andReturn(stackId); + expect(cluster.getResourceId()).andReturn(4l).atLeastOnce(); + expect(cluster.getServices()).andReturn(Collections.singletonMap("Service100", service)).anyTimes(); + expect(cluster.getClusterId()).andReturn(2L).anyTimes(); + + expect(cluster.getService("Service100")).andReturn(service).anyTimes(); + expect(service.getName()).andReturn("Service100").anyTimes(); + expect(service.getServiceComponent("Component101")).andReturn(serviceComponent1).anyTimes(); + + expect(serviceComponent1.getName()).andReturn("Component101").atLeastOnce(); + expect(serviceComponent1.isRecoveryEnabled()).andReturn(false).atLeastOnce(); + serviceComponent1.setRecoveryEnabled(true); + expectLastCall().once(); + + expect(service.getServiceComponents()).andReturn(serviceComponentMap).anyTimes(); + + expect(ambariMetaInfo.getComponent("stackName", "1", "Service100", "Component101")).andReturn(component1Info).atLeastOnce(); + expect(component1Info.getCategory()).andReturn(null); + + expect(serviceComponent1.convertToResponse()).andReturn( + new ServiceComponentResponse(100L, "Cluster100", "Service100", "Component101", null, "", 1, 0, 1, + false /* recovery not enabled */, "Component101 Client")); + expect(serviceComponent1.getDesiredState()).andReturn(State.INSTALLED).anyTimes(); + + expect(serviceComponentHost.getState()).andReturn(State.INSTALLED).anyTimes(); + + Map<String, ServiceComponentHost> serviceComponentHosts = Collections.singletonMap("Host100", serviceComponentHost); + + expect(serviceComponent1.getServiceComponentHosts()).andReturn(serviceComponentHosts).anyTimes(); + + expect(maintenanceStateHelper.isOperationAllowed(anyObject(Resource.Type.class), anyObject(Service.class))).andReturn(true).anyTimes(); + + Capture<Map<String, String>> requestPropertiesCapture = EasyMock.newCapture(); + Capture<Map<State, List<Service>>> changedServicesCapture = EasyMock.newCapture(); + Capture<Map<State, List<ServiceComponent>>> changedCompsCapture = EasyMock.newCapture(); + Capture<Map<String, Map<State, List<ServiceComponentHost>>>> changedScHostsCapture = EasyMock.newCapture(); + Capture<Map<String, String>> requestParametersCapture = EasyMock.newCapture(); + Capture<Collection<ServiceComponentHost>> ignoredScHostsCapture = EasyMock.newCapture(); + Capture<Cluster> clusterCapture = EasyMock.newCapture(); + + expect(managementController.createAndPersistStages(capture(clusterCapture), capture(requestPropertiesCapture), capture(requestParametersCapture), capture(changedServicesCapture), capture(changedCompsCapture), capture(changedScHostsCapture), capture(ignoredScHostsCapture), anyBoolean(), anyBoolean() + )).andReturn(requestStatusResponse); + + Map<String, String> mapRequestProps = new HashMap<String, String>(); + mapRequestProps.put("context", "Called from a test"); + + // replay + replay(managementController, clusters, cluster, ambariMetaInfo, service, component1Info, + serviceComponent1, serviceComponentHost, requestStatusResponse, stackId, maintenanceStateHelper); + + SecurityContextHolder.getContext().setAuthentication(authentication); + + ResourceProvider provider = new ComponentResourceProvider( + PropertyHelper.getPropertyIds(type), + PropertyHelper.getKeyPropertyIds(type), + managementController, maintenanceStateHelper); + + Map<String, Object> properties = new LinkedHashMap<String, Object>(); + + properties.put(ComponentResourceProvider.COMPONENT_RECOVERY_ENABLED_ID, String.valueOf(true) /* recovery enabled */); + + // create the request + Request request = PropertyHelper.getUpdateRequest(properties, mapRequestProps); + + // update the cluster named Cluster100 + Predicate predicate = new PredicateBuilder().property(ComponentResourceProvider.COMPONENT_CLUSTER_NAME_PROPERTY_ID). + equals("Cluster100").toPredicate(); + provider.updateResources(request, predicate); + + // verify + verify(managementController, clusters, cluster, ambariMetaInfo, service, component1Info, + serviceComponent1, serviceComponentHost, requestStatusResponse, stackId, maintenanceStateHelper); + } @Test public void testGetComponents() throws Exception { http://git-wip-us.apache.org/repos/asf/ambari/blob/ae6dbcea/ambari-web/app/views/main/admin.js ---------------------------------------------------------------------- diff --git a/ambari-web/app/views/main/admin.js b/ambari-web/app/views/main/admin.js index 8b9ec03..fc186d8 100644 --- a/ambari-web/app/views/main/admin.js +++ b/ambari-web/app/views/main/admin.js @@ -44,7 +44,7 @@ App.MainAdminView = Em.View.extend({ label: Em.I18n.t('common.kerberos') }); } - if (App.isAuthorized('SERVICE.START_STOP')) { + if (App.isAuthorized('SERVICE.START_STOP, CLUSTER.MODIFY_CONFIGS')) { if (App.supports.serviceAutoStart) { items.push({ name: 'serviceAutoStart', http://git-wip-us.apache.org/repos/asf/ambari/blob/ae6dbcea/ambari-web/app/views/main/menu.js ---------------------------------------------------------------------- diff --git a/ambari-web/app/views/main/menu.js b/ambari-web/app/views/main/menu.js index b71bbd3..e79901b 100644 --- a/ambari-web/app/views/main/menu.js +++ b/ambari-web/app/views/main/menu.js @@ -43,7 +43,7 @@ App.MainMenuView = Em.CollectionView.extend({ {label: Em.I18n.t('menu.item.alerts'), routing: 'alerts'} ); } - if (App.isAuthorized('CLUSTER.TOGGLE_KERBEROS, SERVICE.START_STOP, AMBARI.SET_SERVICE_USERS_GROUPS, CLUSTER.UPGRADE_DOWNGRADE_STACK, CLUSTER.VIEW_STACK_DETAILS')) { + if (App.isAuthorized('CLUSTER.TOGGLE_KERBEROS, CLUSTER.MODIFY_CONFIGS, SERVICE.START_STOP, AMBARI.SET_SERVICE_USERS_GROUPS, CLUSTER.UPGRADE_DOWNGRADE_STACK, CLUSTER.VIEW_STACK_DETAILS')) { result.push({ label: Em.I18n.t('menu.item.admin'), routing: 'admin'}); } } @@ -125,7 +125,7 @@ App.MainMenuView = Em.CollectionView.extend({ label: Em.I18n.t('common.kerberos') }); } - if (App.isAuthorized('SERVICE.START_STOP')) { + if (App.isAuthorized('SERVICE.START_STOP, CLUSTER.MODIFY_CONFIGS')) { if (App.supports.serviceAutoStart) { categories.push({ name: 'serviceAutoStart',
