AMBARI-16177. Views: User should be able to assign permission of a view instance to cluster roles. (dipayanb)
Project: http://git-wip-us.apache.org/repos/asf/ambari/repo Commit: http://git-wip-us.apache.org/repos/asf/ambari/commit/4342a6b7 Tree: http://git-wip-us.apache.org/repos/asf/ambari/tree/4342a6b7 Diff: http://git-wip-us.apache.org/repos/asf/ambari/diff/4342a6b7 Branch: refs/heads/trunk Commit: 4342a6b7eb6eed781d879c46435acc9f0ea8c981 Parents: 7eeab53 Author: Dipayan Bhowmick <dipayan.bhowm...@gmail.com> Authored: Tue Apr 26 12:21:18 2016 +0530 Committer: Dipayan Bhowmick <dipayan.bhowm...@gmail.com> Committed: Tue May 3 23:12:27 2016 +0530 ---------------------------------------------------------------------- .../controllers/ambariViews/ViewsEditCtrl.js | 728 ++++++++++--------- .../ui/admin-web/app/scripts/i18n.config.js | 9 + .../ui/admin-web/app/scripts/services/Group.js | 12 +- .../app/scripts/services/PermissionLoader.js | 10 +- .../app/scripts/services/PermissionsSaver.js | 16 +- .../ui/admin-web/app/scripts/services/View.js | 8 + .../resources/ui/admin-web/app/styles/main.css | 6 + .../admin-web/app/views/ambariViews/edit.html | 85 ++- .../ambari/server/controller/AmbariServer.java | 2 +- .../server/controller/ControllerModule.java | 2 + .../GroupPrivilegeResourceProvider.java | 24 +- .../internal/PrivilegeResourceProvider.java | 3 + .../internal/UserPrivilegeResourceProvider.java | 37 +- .../ambari/server/orm/dao/PrincipalDAO.java | 8 + .../server/orm/entities/PrincipalEntity.java | 3 +- .../orm/entities/PrincipalTypeEntity.java | 10 + .../authorization/AuthorizationHelper.java | 73 +- .../ClusterInheritedPermissionHelper.java | 213 ++++++ .../server/upgrade/AbstractUpgradeCatalog.java | 36 + .../server/upgrade/UpgradeCatalog240.java | 27 + .../apache/ambari/server/view/ViewRegistry.java | 57 +- .../view/configuration/AutoInstanceConfig.java | 27 + .../main/resources/Ambari-DDL-Derby-CREATE.sql | 28 +- .../main/resources/Ambari-DDL-MySQL-CREATE.sql | 28 +- .../main/resources/Ambari-DDL-Oracle-CREATE.sql | 28 +- .../resources/Ambari-DDL-Postgres-CREATE.sql | 28 +- .../Ambari-DDL-Postgres-EMBEDDED-CREATE.sql | 28 +- .../resources/Ambari-DDL-SQLAnywhere-CREATE.sql | 28 +- .../resources/Ambari-DDL-SQLServer-CREATE.sql | 19 +- .../AlertDefinitionResourceProviderTest.java | 2 + .../AlertGroupResourceProviderTest.java | 2 + .../AlertHistoryResourceProviderTest.java | 2 + .../AlertNoticeResourceProviderTest.java | 2 + .../internal/AlertResourceProviderTest.java | 2 + .../internal/ComponentResourceProviderTest.java | 2 + .../GroupPrivilegeResourceProviderTest.java | 19 +- .../internal/HostResourceProviderTest.java | 3 + .../internal/RequestResourceProviderTest.java | 3 + .../UserPrivilegeResourceProviderTest.java | 129 +++- .../metrics/JMXPropertyProviderTest.java | 2 + .../ganglia/GangliaPropertyProviderTest.java | 2 + .../AuthorizationHelperInitializer.java | 47 ++ .../authorization/AuthorizationHelperTest.java | 109 ++- .../server/upgrade/UpgradeCatalog240Test.java | 51 ++ .../configuration/AutoInstanceConfigTest.java | 10 + 45 files changed, 1488 insertions(+), 482 deletions(-) ---------------------------------------------------------------------- http://git-wip-us.apache.org/repos/asf/ambari/blob/4342a6b7/ambari-admin/src/main/resources/ui/admin-web/app/scripts/controllers/ambariViews/ViewsEditCtrl.js ---------------------------------------------------------------------- diff --git a/ambari-admin/src/main/resources/ui/admin-web/app/scripts/controllers/ambariViews/ViewsEditCtrl.js b/ambari-admin/src/main/resources/ui/admin-web/app/scripts/controllers/ambariViews/ViewsEditCtrl.js index 877e230..243a8e4 100644 --- a/ambari-admin/src/main/resources/ui/admin-web/app/scripts/controllers/ambariViews/ViewsEditCtrl.js +++ b/ambari-admin/src/main/resources/ui/admin-web/app/scripts/controllers/ambariViews/ViewsEditCtrl.js @@ -18,402 +18,412 @@ 'use strict'; angular.module('ambariAdminConsole') -.controller('ViewsEditCtrl', ['$scope', '$routeParams' , 'Cluster', 'View', 'Alert', 'PermissionLoader', 'PermissionSaver', 'ConfirmationModal', '$location', 'UnsavedDialog', '$translate', function($scope, $routeParams, Cluster, View, Alert, PermissionLoader, PermissionSaver, ConfirmationModal, $location, UnsavedDialog, $translate) { - var $t = $translate.instant; - $scope.identity = angular.identity; - $scope.isConfigurationEmpty = true; - $scope.isSettingsEmpty = true; - $scope.constants = { - instance: $t('views.instance'), - props: $t('views.properties'), - perms: $t('views.permissions').toLowerCase() - }; - - function reloadViewInfo(section){ - // Load instance data, after View permissions meta loaded - View.getInstance($routeParams.viewId, $routeParams.version, $routeParams.instanceId) - .then(function(instance) { - $scope.instance = instance; - $scope.settings = { - 'visible': $scope.instance.ViewInstanceInfo.visible, - 'label': $scope.instance.ViewInstanceInfo.label, - 'description': $scope.instance.ViewInstanceInfo.description, - 'shortUrl': $scope.instance.ViewInstanceInfo.short_url - }; - switch (section) { - case "details" : - initConfigurations(); - initCtrlVariables(instance); - break; - case "settings" : - initConfigurations(true); - break; - case "cluster" : - initCtrlVariables(instance); - break; - } - }) - .catch(function(data) { - Alert.error($t('views.alerts.cannotLoadInstanceInfo'), data.data.message); - }); - } - - function initCtrlVariables(instance) { - if(instance.ViewInstanceInfo.cluster_handle) { - $scope.isLocalCluster = true; - $scope.cluster = instance.ViewInstanceInfo.cluster_handle; - }else{ - $scope.isLocalCluster = false; - $scope.cluster = $scope.clusters.length > 0 ? $scope.clusters[0] : $t('common.noClusters'); - } - $scope.originalLocalCluster = $scope.isLocalCluster; - $scope.isConfigurationEmpty = !$scope.numberOfClusterConfigs; - $scope.isSettingsEmpty = !$scope.numberOfSettingsConfigs; - } - - function isClusterConfig(name) { - var configurationMeta = $scope.configurationMeta; - var clusterConfigs = configurationMeta.filter(function(el) { - return el.clusterConfig; - }).map(function(el) { - return el.name; - }); - return clusterConfigs.indexOf(name) !== -1; - } - - function initConfigurations(initClusterConfig) { - var initAllConfigs = !initClusterConfig; - var configuration = angular.copy($scope.instance.ViewInstanceInfo.properties); - if (initAllConfigs) { - $scope.configuration = angular.copy($scope.instance.ViewInstanceInfo.properties); + .controller('ViewsEditCtrl', ['$scope', '$routeParams' , 'Cluster', 'View', 'Alert', 'PermissionLoader', 'PermissionSaver', 'ConfirmationModal', '$location', 'UnsavedDialog', '$translate', function($scope, $routeParams, Cluster, View, Alert, PermissionLoader, PermissionSaver, ConfirmationModal, $location, UnsavedDialog, $translate) { + var $t = $translate.instant; + $scope.identity = angular.identity; + $scope.isConfigurationEmpty = true; + $scope.isSettingsEmpty = true; + $scope.clusterInheritedPermissionKeys = View.clusterInheritedPermissionKeys; + $scope.constants = { + instance: $t('views.instance'), + props: $t('views.properties'), + perms: $t('views.permissions').toLowerCase() + }; + + function reloadViewInfo(section){ + // Load instance data, after View permissions meta loaded + View.getInstance($routeParams.viewId, $routeParams.version, $routeParams.instanceId) + .then(function(instance) { + $scope.instance = instance; + $scope.settings = { + 'visible': $scope.instance.ViewInstanceInfo.visible, + 'label': $scope.instance.ViewInstanceInfo.label, + 'description': $scope.instance.ViewInstanceInfo.description, + 'shortUrl': $scope.instance.ViewInstanceInfo.short_url + }; + switch (section) { + case "details" : + initConfigurations(); + initCtrlVariables(instance); + break; + case "settings" : + initConfigurations(true); + break; + case "cluster" : + initCtrlVariables(instance); + break; + } + }) + .catch(function(data) { + Alert.error($t('views.alerts.cannotLoadInstanceInfo'), data.data.message); + }); } - for (var confName in configuration) { - if (configuration.hasOwnProperty(confName)) { - if (!isClusterConfig(confName) || initAllConfigs) { - $scope.configuration[confName] = configuration[confName] === 'null' ? '' : configuration[confName]; - } + + function initCtrlVariables(instance) { + if(instance.ViewInstanceInfo.cluster_handle) { + $scope.isLocalCluster = true; + $scope.cluster = instance.ViewInstanceInfo.cluster_handle; + }else{ + $scope.isLocalCluster = false; + $scope.cluster = $scope.clusters.length > 0 ? $scope.clusters[0] : $t('common.noClusters'); } + $scope.originalLocalCluster = $scope.isLocalCluster; + $scope.isConfigurationEmpty = !$scope.numberOfClusterConfigs; + $scope.isSettingsEmpty = !$scope.numberOfSettingsConfigs; } - } - function filterClusterConfigs() { - $scope.configurationMeta.forEach(function (element) { - if (element.masked && !$scope.editConfigurationDisabled && element.clusterConfig && !$scope.isLocalCluster) { - $scope.configuration[element.name] = ''; - } - if(!element.clusterConfig) { - delete $scope.configurationBeforeEdit[element.name]; + function isClusterConfig(name) { + var configurationMeta = $scope.configurationMeta; + var clusterConfigs = configurationMeta.filter(function(el) { + return el.clusterConfig; + }).map(function(el) { + return el.name; + }); + return clusterConfigs.indexOf(name) !== -1; + } + + function initConfigurations(initClusterConfig) { + var initAllConfigs = !initClusterConfig; + var configuration = angular.copy($scope.instance.ViewInstanceInfo.properties); + if (initAllConfigs) { + $scope.configuration = angular.copy($scope.instance.ViewInstanceInfo.properties); } - }); - } - - // Get META for properties - View.getMeta($routeParams.viewId, $routeParams.version).then(function(data) { - $scope.configurationMeta = data.data.ViewVersionInfo.parameters; - $scope.clusterConfigurable = data.data.ViewVersionInfo.cluster_configurable; - $scope.clusterConfigurableErrorMsg = $scope.clusterConfigurable ? "" : $t('views.alerts.cannotUseOption'); - angular.forEach($scope.configurationMeta, function (item) { - item.displayName = item.name.replace(/\./g, '\.\u200B'); - item.clusterConfig = !!item.clusterConfig; - if (!item.clusterConfig) { - $scope.numberOfSettingsConfigs++; + for (var confName in configuration) { + if (configuration.hasOwnProperty(confName)) { + if (!isClusterConfig(confName) || initAllConfigs) { + $scope.configuration[confName] = configuration[confName] === 'null' ? '' : configuration[confName]; + } + } } - $scope.numberOfClusterConfigs = $scope.numberOfClusterConfigs + !!item.clusterConfig; - }); - reloadViewInfo("details"); - }); - - function reloadViewPrivileges(){ - PermissionLoader.getViewPermissions({ - viewName: $routeParams.viewId, - version: $routeParams.version, - instanceId: $routeParams.instanceId - }) - .then(function(permissions) { - // Refresh data for rendering - $scope.permissionsEdit = permissions; - $scope.permissions = angular.copy(permissions); - $scope.isPermissionsEmpty = angular.equals({}, $scope.permissions); - }) - .catch(function(data) { - Alert.error($t('views.alerts.cannotLoadPermissions'), data.data.message); - }); - } + } - $scope.permissions = []; + function filterClusterConfigs() { + $scope.configurationMeta.forEach(function (element) { + if (element.masked && !$scope.editConfigurationDisabled && element.clusterConfig && !$scope.isLocalCluster) { + $scope.configuration[element.name] = ''; + } + if(!element.clusterConfig) { + delete $scope.configurationBeforeEdit[element.name]; + } + }); + } - reloadViewPrivileges(); + // Get META for properties + View.getMeta($routeParams.viewId, $routeParams.version).then(function(data) { + $scope.configurationMeta = data.data.ViewVersionInfo.parameters; + $scope.clusterConfigurable = data.data.ViewVersionInfo.cluster_configurable; + $scope.clusterConfigurableErrorMsg = $scope.clusterConfigurable ? "" : $t('views.alerts.cannotUseOption'); + angular.forEach($scope.configurationMeta, function (item) { + item.displayName = item.name.replace(/\./g, '\.\u200B'); + item.clusterConfig = !!item.clusterConfig; + if (!item.clusterConfig) { + $scope.numberOfSettingsConfigs++; + } + $scope.numberOfClusterConfigs = $scope.numberOfClusterConfigs + !!item.clusterConfig; + }); + reloadViewInfo("details"); + }); - $scope.clusterConfigurable = false; - $scope.clusterConfigurableErrorMsg = ""; - $scope.clusters = []; - $scope.cluster = null; - $scope.noClusterAvailible = true; + function reloadViewPrivileges(){ + PermissionLoader.getViewPermissions({ + viewName: $routeParams.viewId, + version: $routeParams.version, + instanceId: $routeParams.instanceId + }) + .then(function(permissions) { + // Refresh data for rendering + $scope.permissionsEdit = permissions; + $scope.permissions = angular.copy(permissions); + $scope.isPermissionsEmpty = angular.equals({}, $scope.permissions); + }) + .catch(function(data) { + Alert.error($t('views.alerts.cannotLoadPermissions'), data.data.message); + }); + } + $scope.permissions = []; - $scope.editSettingsDisabled = true; - $scope.editDetailsSettingsDisabled = true; - $scope.numberOfClusterConfigs = 0; - $scope.numberOfSettingsConfigs = 0; + reloadViewPrivileges(); - $scope.enableLocalCluster = function() { - angular.extend($scope.configuration, $scope.configurationBeforeEdit); - $scope.propertiesForm.$setPristine(); - }; + $scope.clusterConfigurable = false; + $scope.clusterConfigurableErrorMsg = ""; + $scope.clusters = []; + $scope.cluster = null; + $scope.noClusterAvailible = true; - $scope.disableLocalCluster = function() { - filterClusterConfigs(); - }; - $scope.toggleSettingsEdit = function() { - $scope.editSettingsDisabled = !$scope.editSettingsDisabled; - $scope.settingsBeforeEdit = angular.copy($scope.configuration); - $scope.configurationMeta.forEach(function (element) { - if (element.masked && !$scope.editSettingsDisabled && !element.clusterConfig) { - $scope.configuration[element.name] = ''; - } - if(element.clusterConfig) { - delete $scope.settingsBeforeEdit[element.name]; - } - }); - }; - - $scope.toggleDetailsSettingsEdit = function() { - $scope.editDetailsSettingsDisabled = !$scope.editDetailsSettingsDisabled; - $scope.settingsBeforeEdit = angular.copy($scope.configuration); - $scope.configurationMeta.forEach(function (element) { - if (element.masked && !$scope.editDetailsSettingsDisabled && !element.clusterConfig) { - $scope.configuration[element.name] = ''; - } - if(element.clusterConfig) { - delete $scope.settingsBeforeEdit[element.name]; - } - }); - }; + $scope.editSettingsDisabled = true; + $scope.editDetailsSettingsDisabled = true; + $scope.numberOfClusterConfigs = 0; + $scope.numberOfSettingsConfigs = 0; - Cluster.getAllClusters().then(function (clusters) { - if(clusters.length >0){ - clusters.forEach(function(cluster) { - $scope.clusters.push(cluster.Clusters.cluster_name) - }); - $scope.noClusterAvailible = false; - }else{ - $scope.clusters.push($t('common.noClusters')); - } - $scope.cluster = $scope.clusters[0]; - }); + $scope.enableLocalCluster = function() { + angular.extend($scope.configuration, $scope.configurationBeforeEdit); + $scope.propertiesForm.$setPristine(); + }; + $scope.disableLocalCluster = function() { + filterClusterConfigs(); + }; - $scope.saveSettings = function(callback) { - if( $scope.settingsForm.$valid ){ - var data = { - 'ViewInstanceInfo':{ - 'properties':{} - } - }; + $scope.toggleSettingsEdit = function() { + $scope.editSettingsDisabled = !$scope.editSettingsDisabled; + $scope.settingsBeforeEdit = angular.copy($scope.configuration); $scope.configurationMeta.forEach(function (element) { - if(!element.clusterConfig) { - data.ViewInstanceInfo.properties[element.name] = $scope.configuration[element.name]; + if (element.masked && !$scope.editSettingsDisabled && !element.clusterConfig) { + $scope.configuration[element.name] = ''; } - }); - return View.updateInstance($routeParams.viewId, $routeParams.version, $routeParams.instanceId, data) - .success(function() { - if( callback ){ - callback(); - } else { - reloadViewInfo("settings"); - $scope.editSettingsDisabled = true; - $scope.settingsForm.$setPristine(); + if(element.clusterConfig) { + delete $scope.settingsBeforeEdit[element.name]; } - }) - .catch(function(data) { - Alert.error($t('views.alerts.cannotSaveSettings'), data.data.message); }); - } - }; - $scope.cancelSettings = function() { - angular.extend($scope.configuration, $scope.settingsBeforeEdit); + }; - $scope.editSettingsDisabled = true; - $scope.settingsForm.$setPristine(); - }; - - $scope.saveDetails = function(callback) { - if( $scope.detailsForm.$valid ){ - var data = { - 'ViewInstanceInfo':{ - 'visible': $scope.settings.visible, - 'label': $scope.settings.label, - 'description': $scope.settings.description + $scope.toggleDetailsSettingsEdit = function() { + $scope.editDetailsSettingsDisabled = !$scope.editDetailsSettingsDisabled; + $scope.settingsBeforeEdit = angular.copy($scope.configuration); + $scope.configurationMeta.forEach(function (element) { + if (element.masked && !$scope.editDetailsSettingsDisabled && !element.clusterConfig) { + $scope.configuration[element.name] = ''; } - }; - return View.updateInstance($routeParams.viewId, $routeParams.version, $routeParams.instanceId, data) - .success(function() { - $scope.$root.$emit('instancesUpdate'); - if( callback ){ - callback(); - } else { - reloadViewInfo("cluster"); - $scope.editDetailsSettingsDisabled = true; - $scope.settingsForm.$setPristine(); + if(element.clusterConfig) { + delete $scope.settingsBeforeEdit[element.name]; } - }) - .catch(function(data) { - Alert.error($t('views.alerts.cannotSaveSettings'), data.data.message); }); - } - }; - $scope.cancelDetails = function() { - $scope.settings = { - 'visible': $scope.instance.ViewInstanceInfo.visible, - 'label': $scope.instance.ViewInstanceInfo.label, - 'description': $scope.instance.ViewInstanceInfo.description, - 'shortUrl': $scope.instance.ViewInstanceInfo.short_url }; - $scope.editDetailsSettingsDisabled = true; - $scope.settingsForm.$setPristine(); - }; - - - $scope.editConfigurationDisabled = true; - $scope.togglePropertiesEditing = function () { - $scope.editConfigurationDisabled = !$scope.editConfigurationDisabled; - $scope.configurationBeforeEdit = angular.copy($scope.configuration); - filterClusterConfigs(); - }; - $scope.saveConfiguration = function() { - if( $scope.propertiesForm.$valid ){ - var data = { - 'ViewInstanceInfo':{ - 'properties':{} - } - }; - if($scope.isLocalCluster) { - data.ViewInstanceInfo.cluster_handle = $scope.cluster; - } else { - data.ViewInstanceInfo.cluster_handle = null; + + Cluster.getAllClusters().then(function (clusters) { + if(clusters.length >0){ + clusters.forEach(function(cluster) { + $scope.clusters.push(cluster.Clusters.cluster_name) + }); + $scope.noClusterAvailible = false; + }else{ + $scope.clusters.push($t('common.noClusters')); + } + $scope.cluster = $scope.clusters[0]; + }); + + + $scope.saveSettings = function(callback) { + if( $scope.settingsForm.$valid ){ + var data = { + 'ViewInstanceInfo':{ + 'properties':{} + } + }; $scope.configurationMeta.forEach(function (element) { - if(element.clusterConfig) { + if(!element.clusterConfig) { data.ViewInstanceInfo.properties[element.name] = $scope.configuration[element.name]; } }); + return View.updateInstance($routeParams.viewId, $routeParams.version, $routeParams.instanceId, data) + .success(function() { + if( callback ){ + callback(); + } else { + reloadViewInfo("settings"); + $scope.editSettingsDisabled = true; + $scope.settingsForm.$setPristine(); + } + }) + .catch(function(data) { + Alert.error($t('views.alerts.cannotSaveSettings'), data.data.message); + }); } - $scope.originalLocalCluster = $scope.isLocalCluster; - return View.updateInstance($routeParams.viewId, $routeParams.version, $routeParams.instanceId, data) - .success(function() { - $scope.editConfigurationDisabled = true; - $scope.propertiesForm.$setPristine(); - }) - .catch(function(data) { - var errorMessage = data.data.message; - - //TODO: maybe the BackEnd should sanitize the string beforehand? - errorMessage = errorMessage.substr(errorMessage.indexOf("\{")); - - if (data.status >= 400 && !$scope.isLocalCluster) { - try { - var errorObject = JSON.parse(errorMessage); - errorMessage = errorObject.detail; - angular.forEach(errorObject.propertyResults, function (item, key) { - $scope.propertiesForm[key].validationError = !item.valid; - if (!item.valid) { - $scope.propertiesForm[key].validationMessage = item.detail; - } - }); - } catch (e) { - console.error($t('views.alerts.unableToParseError', {message: data.message})); + }; + $scope.cancelSettings = function() { + angular.extend($scope.configuration, $scope.settingsBeforeEdit); + + $scope.editSettingsDisabled = true; + $scope.settingsForm.$setPristine(); + }; + + $scope.saveDetails = function(callback) { + if( $scope.detailsForm.$valid ){ + var data = { + 'ViewInstanceInfo':{ + 'visible': $scope.settings.visible, + 'label': $scope.settings.label, + 'description': $scope.settings.description } - } - Alert.error($t('views.alerts.cannotSaveProperties'), errorMessage); - }); - } - }; - $scope.cancelConfiguration = function() { - angular.extend($scope.configuration, $scope.configurationBeforeEdit); - $scope.isLocalCluster = $scope.originalLocalCluster; + }; + return View.updateInstance($routeParams.viewId, $routeParams.version, $routeParams.instanceId, data) + .success(function() { + $scope.$root.$emit('instancesUpdate'); + if( callback ){ + callback(); + } else { + reloadViewInfo("cluster"); + $scope.editDetailsSettingsDisabled = true; + $scope.settingsForm.$setPristine(); + } + }) + .catch(function(data) { + Alert.error($t('views.alerts.cannotSaveSettings'), data.data.message); + }); + } + }; + $scope.cancelDetails = function() { + $scope.settings = { + 'visible': $scope.instance.ViewInstanceInfo.visible, + 'label': $scope.instance.ViewInstanceInfo.label, + 'description': $scope.instance.ViewInstanceInfo.description, + 'shortUrl': $scope.instance.ViewInstanceInfo.short_url + }; + $scope.editDetailsSettingsDisabled = true; + $scope.settingsForm.$setPristine(); + }; + + $scope.editConfigurationDisabled = true; - $scope.propertiesForm.$setPristine(); - }; + $scope.togglePropertiesEditing = function () { + $scope.editConfigurationDisabled = !$scope.editConfigurationDisabled; + $scope.configurationBeforeEdit = angular.copy($scope.configuration); + filterClusterConfigs(); + }; + $scope.saveConfiguration = function() { + if( $scope.propertiesForm.$valid ){ + var data = { + 'ViewInstanceInfo':{ + 'properties':{} + } + }; + if($scope.isLocalCluster) { + data.ViewInstanceInfo.cluster_handle = $scope.cluster; + } else { + data.ViewInstanceInfo.cluster_handle = null; + $scope.configurationMeta.forEach(function (element) { + if(element.clusterConfig) { + data.ViewInstanceInfo.properties[element.name] = $scope.configuration[element.name]; + } + }); + $scope.clearClusterInheritedPermissions(); + } + $scope.originalLocalCluster = $scope.isLocalCluster; + return View.updateInstance($routeParams.viewId, $routeParams.version, $routeParams.instanceId, data) + .success(function() { + $scope.editConfigurationDisabled = true; + $scope.propertiesForm.$setPristine(); + }) + .catch(function(data) { + var errorMessage = data.data.message; - // Permissions edit - $scope.editPermissionDisabled = true; - $scope.cancelPermissions = function() { - $scope.permissionsEdit = angular.copy($scope.permissions); // Reset textedit areaes - $scope.editPermissionDisabled = true; - }; + //TODO: maybe the BackEnd should sanitize the string beforehand? + errorMessage = errorMessage.substr(errorMessage.indexOf("\{")); - $scope.savePermissions = function() { - $scope.editPermissionDisabled = true; - return PermissionSaver.saveViewPermissions( - $scope.permissionsEdit, - { - view_name: $routeParams.viewId, - version: $routeParams.version, - instance_name: $routeParams.instanceId + if (data.status >= 400 && !$scope.isLocalCluster) { + try { + var errorObject = JSON.parse(errorMessage); + errorMessage = errorObject.detail; + angular.forEach(errorObject.propertyResults, function (item, key) { + $scope.propertiesForm[key].validationError = !item.valid; + if (!item.valid) { + $scope.propertiesForm[key].validationMessage = item.detail; + } + }); + } catch (e) { + console.error($t('views.alerts.unableToParseError', {message: data.message})); + } + } + Alert.error($t('views.alerts.cannotSaveProperties'), errorMessage); + }); } - ) - .then(reloadViewPrivileges) - .catch(function(data) { - reloadViewPrivileges(); - Alert.error($t('common.alerts.cannotSavePermissions'), data.data.message); - }); - }; + }; + $scope.cancelConfiguration = function() { + angular.extend($scope.configuration, $scope.configurationBeforeEdit); + $scope.isLocalCluster = $scope.originalLocalCluster; + $scope.editConfigurationDisabled = true; + $scope.propertiesForm.$setPristine(); + }; - $scope.$watch(function() { - return $scope.permissionsEdit; - }, function(newValue) { - if(newValue){ - $scope.savePermissions(); - } - }, true); - - $scope.deleteInstance = function(instance) { - ConfirmationModal.show( - $t('common.delete', { - term: $t('views.viewInstance') - }), - $t('common.deleteConfirmation', { - instanceType: $t('views.viewInstance'), - instanceName: instance.ViewInstanceInfo.label - }) - ).then(function() { - View.deleteInstance(instance.ViewInstanceInfo.view_name, instance.ViewInstanceInfo.version, instance.ViewInstanceInfo.instance_name) - .then(function() { - $location.path('/views'); + // Permissions edit + $scope.editPermissionDisabled = true; + $scope.cancelPermissions = function() { + $scope.permissionsEdit = angular.copy($scope.permissions); // Reset textedit areaes + $scope.editPermissionDisabled = true; + }; + + $scope.savePermissions = function() { + $scope.editPermissionDisabled = true; + return PermissionSaver.saveViewPermissions( + $scope.permissionsEdit, + { + view_name: $routeParams.viewId, + version: $routeParams.version, + instance_name: $routeParams.instanceId + } + ) + .then(reloadViewPrivileges) + .catch(function(data) { + reloadViewPrivileges(); + Alert.error($t('common.alerts.cannotSavePermissions'), data.data.message); + }); + }; + + $scope.clearClusterInheritedPermissions = function() { + angular.forEach(View.clusterInheritedPermissionKeys, function(key) { + $scope.permissionsEdit["VIEW.USER"][key] = false; }) - .catch(function(data) { - Alert.error($t('views.alerts.cannotDeleteInstance'), data.data.message); + }; + + $scope.$watch(function() { + return $scope.permissionsEdit; + }, function(newValue, oldValue) { + if(newValue && oldValue != undefined) { + $scope.savePermissions(); + } + }, true); + + + + $scope.deleteInstance = function(instance) { + ConfirmationModal.show( + $t('common.delete', { + term: $t('views.viewInstance') + }), + $t('common.deleteConfirmation', { + instanceType: $t('views.viewInstance'), + instanceName: instance.ViewInstanceInfo.label + }) + ).then(function() { + View.deleteInstance(instance.ViewInstanceInfo.view_name, instance.ViewInstanceInfo.version, instance.ViewInstanceInfo.instance_name) + .then(function() { + $location.path('/views'); + }) + .catch(function(data) { + Alert.error($t('views.alerts.cannotDeleteInstance'), data.data.message); + }); }); - }); - }; - - $scope.$on('$locationChangeStart', function(event, targetUrl) { - if( $scope.settingsForm.$dirty || $scope.propertiesForm.$dirty){ - UnsavedDialog().then(function(action) { - targetUrl = targetUrl.split('#').pop(); - switch(action){ - case 'save': - if($scope.settingsForm.$valid && $scope.propertiesForm.$valid ){ - $scope.saveSettings(function() { - $scope.saveConfiguration().then(function() { - $scope.propertiesForm.$setPristine(); - $scope.settingsForm.$setPristine(); - $location.path(targetUrl); + }; + + $scope.$on('$locationChangeStart', function(event, targetUrl) { + if( $scope.settingsForm.$dirty || $scope.propertiesForm.$dirty){ + UnsavedDialog().then(function(action) { + targetUrl = targetUrl.split('#').pop(); + switch(action){ + case 'save': + if($scope.settingsForm.$valid && $scope.propertiesForm.$valid ){ + $scope.saveSettings(function() { + $scope.saveConfiguration().then(function() { + $scope.propertiesForm.$setPristine(); + $scope.settingsForm.$setPristine(); + $location.path(targetUrl); + }); }); - }); - } - break; - case 'discard': - $scope.propertiesForm.$setPristine(); - $scope.settingsForm.$setPristine(); - $location.path(targetUrl); - break; - case 'cancel': - targetUrl = ''; - break; - } - }); - event.preventDefault(); - } - }); -}]); + } + break; + case 'discard': + $scope.propertiesForm.$setPristine(); + $scope.settingsForm.$setPristine(); + $location.path(targetUrl); + break; + case 'cancel': + targetUrl = ''; + break; + } + }); + event.preventDefault(); + } + }); + }]); http://git-wip-us.apache.org/repos/asf/ambari/blob/4342a6b7/ambari-admin/src/main/resources/ui/admin-web/app/scripts/i18n.config.js ---------------------------------------------------------------------- diff --git a/ambari-admin/src/main/resources/ui/admin-web/app/scripts/i18n.config.js b/ambari-admin/src/main/resources/ui/admin-web/app/scripts/i18n.config.js index 6af7d4c..175792c 100644 --- a/ambari-admin/src/main/resources/ui/admin-web/app/scripts/i18n.config.js +++ b/ambari-admin/src/main/resources/ui/admin-web/app/scripts/i18n.config.js @@ -209,6 +209,15 @@ angular.module('ambariAdminConsole') 'urlCreate':'Create new URL', 'urlDelete':'Delete URL', + 'clusterPermissions': { + 'label': 'Inherit Cluster Permission', + 'allclusteradministrator': 'All Cluster Administrator', + 'allclusteroperator': 'All Cluster Operator', + 'allclusteruser': 'All Cluster User', + 'allserviceadministrator': 'All Service Administrator', + 'allserviceoperator': 'All Service Operator' + }, + 'alerts': { 'noSpecialChars': 'Must not contain any special characters.', 'noSpecialCharsOrSpaces': 'Must not contain any special characters or spaces.', http://git-wip-us.apache.org/repos/asf/ambari/blob/4342a6b7/ambari-admin/src/main/resources/ui/admin-web/app/scripts/services/Group.js ---------------------------------------------------------------------- diff --git a/ambari-admin/src/main/resources/ui/admin-web/app/scripts/services/Group.js b/ambari-admin/src/main/resources/ui/admin-web/app/scripts/services/Group.js index ce892ec..660306c 100644 --- a/ambari-admin/src/main/resources/ui/admin-web/app/scripts/services/Group.js +++ b/ambari-admin/src/main/resources/ui/admin-web/app/scripts/services/Group.js @@ -181,13 +181,11 @@ angular.module('ambariAdminConsole') }; Group.getPrivileges = function(groupId) { - return $http.get(Settings.baseUrl + '/privileges', { - params:{ - 'PrivilegeInfo/principal_type': 'GROUP', - 'PrivilegeInfo/principal_name': groupId, - 'fields': '*' - } - }); + return $http.get(Settings.baseUrl + '/groups/' + groupId + '/privileges', { + params:{ + 'fields': '*' + } + }); }; return Group; http://git-wip-us.apache.org/repos/asf/ambari/blob/4342a6b7/ambari-admin/src/main/resources/ui/admin-web/app/scripts/services/PermissionLoader.js ---------------------------------------------------------------------- diff --git a/ambari-admin/src/main/resources/ui/admin-web/app/scripts/services/PermissionLoader.js b/ambari-admin/src/main/resources/ui/admin-web/app/scripts/services/PermissionLoader.js index cc56191..13db1e6 100644 --- a/ambari-admin/src/main/resources/ui/admin-web/app/scripts/services/PermissionLoader.js +++ b/ambari-admin/src/main/resources/ui/admin-web/app/scripts/services/PermissionLoader.js @@ -22,18 +22,26 @@ angular.module('ambariAdminConsole') function getPermissionsFor(resource, params){ var deferred = $q.defer(); + resource.getPermissions(params).then(function(permissions) { var permissionsInner = {}; // Save object into closure, until it completely fills to prevent blinkong angular.forEach(permissions, function(permission) { permission.GROUP = []; permission.USER = []; + angular.forEach(View.clusterInheritedPermissionKeys, function(key) { + permission[key] = false; + }); permissionsInner[permission.PermissionInfo.permission_name] = permission; }); // Now we can get privileges resource.getPrivileges(params).then(function(privileges) { angular.forEach(privileges, function(privilege) { - permissionsInner[privilege.PrivilegeInfo.permission_name][privilege.PrivilegeInfo.principal_type].push(privilege.PrivilegeInfo.principal_name); + if(!privilege.PrivilegeInfo.principal_type.startsWith("ALL.")) { + permissionsInner[privilege.PrivilegeInfo.permission_name][privilege.PrivilegeInfo.principal_type].push(privilege.PrivilegeInfo.principal_name); + } else { + permissionsInner[privilege.PrivilegeInfo.permission_name][privilege.PrivilegeInfo.principal_type] = true; + } }); // After all builded - return object http://git-wip-us.apache.org/repos/asf/ambari/blob/4342a6b7/ambari-admin/src/main/resources/ui/admin-web/app/scripts/services/PermissionsSaver.js ---------------------------------------------------------------------- diff --git a/ambari-admin/src/main/resources/ui/admin-web/app/scripts/services/PermissionsSaver.js b/ambari-admin/src/main/resources/ui/admin-web/app/scripts/services/PermissionsSaver.js index fd19e1f..bebd668 100644 --- a/ambari-admin/src/main/resources/ui/admin-web/app/scripts/services/PermissionsSaver.js +++ b/ambari-admin/src/main/resources/ui/admin-web/app/scripts/services/PermissionsSaver.js @@ -23,7 +23,6 @@ angular.module('ambariAdminConsole') function savePermissionsFor(resource, permissions, params){ var arr = []; - angular.forEach(permissions, function(permission) { // Sanitaize input var users = permission.USER.toString().split(',').filter(function(item) {return item.trim();}).map(function(item) {return item.trim()}); @@ -48,6 +47,19 @@ angular.module('ambariAdminConsole') } } })); + + angular.forEach(View.clusterInheritedPermissionKeys, function(key) { + if(permission[key] === true) { + arr.push({ + 'PrivilegeInfo': { + 'permission_name': 'VIEW.USER', + 'principal_name': '*', + 'principal_type': key + } + }); + } + }); + }); if (!passOneRoleCheck(arr)) { console.log("CHECK FAILED"); @@ -143,7 +155,7 @@ angular.module('ambariAdminConsole') var hash = {}; for(var i = 0; i < arr.length; i++) { var obj = arr[i]; - if (hash[obj.PrivilegeInfo.principal_name]) { + if (hash[obj.PrivilegeInfo.principal_name] && obj.PrivilegeInfo.principal_name !== "*") { return false; } else { hash[obj.PrivilegeInfo.principal_name] = true; http://git-wip-us.apache.org/repos/asf/ambari/blob/4342a6b7/ambari-admin/src/main/resources/ui/admin-web/app/scripts/services/View.js ---------------------------------------------------------------------- diff --git a/ambari-admin/src/main/resources/ui/admin-web/app/scripts/services/View.js b/ambari-admin/src/main/resources/ui/admin-web/app/scripts/services/View.js index edc47e4..d352508 100644 --- a/ambari-admin/src/main/resources/ui/admin-web/app/scripts/services/View.js +++ b/ambari-admin/src/main/resources/ui/admin-web/app/scripts/services/View.js @@ -190,6 +190,14 @@ angular.module('ambariAdminConsole') self.versionsList = item.versions; } + View.clusterInheritedPermissionKeys = [ + "ALL.CLUSTER.ADMINISTRATOR", + "ALL.CLUSTER.OPERATOR", + "ALL.CLUSTER.USER", + "ALL.SERVICE.OPERATOR", + "ALL.SERVICE.ADMINISTRATOR" + ]; + View.getInstance = function(viewName, version, instanceName) { return ViewInstance.find(viewName, version, instanceName); }; http://git-wip-us.apache.org/repos/asf/ambari/blob/4342a6b7/ambari-admin/src/main/resources/ui/admin-web/app/styles/main.css ---------------------------------------------------------------------- diff --git a/ambari-admin/src/main/resources/ui/admin-web/app/styles/main.css b/ambari-admin/src/main/resources/ui/admin-web/app/styles/main.css index 7309cfb..3e0bd30 100644 --- a/ambari-admin/src/main/resources/ui/admin-web/app/styles/main.css +++ b/ambari-admin/src/main/resources/ui/admin-web/app/styles/main.css @@ -1652,4 +1652,10 @@ thead.view-permission-header > tr > th { .role-details-modal .table-head .table-cell:last-of-type { visibility: hidden; +} + +.cluster-inherited-permission { + border-bottom: 2px solid #ddd; + padding-bottom: 10px; + margin-top: 5px; } \ No newline at end of file http://git-wip-us.apache.org/repos/asf/ambari/blob/4342a6b7/ambari-admin/src/main/resources/ui/admin-web/app/views/ambariViews/edit.html ---------------------------------------------------------------------- diff --git a/ambari-admin/src/main/resources/ui/admin-web/app/views/ambariViews/edit.html b/ambari-admin/src/main/resources/ui/admin-web/app/views/ambariViews/edit.html index 8eff030..fb37571 100644 --- a/ambari-admin/src/main/resources/ui/admin-web/app/views/ambariViews/edit.html +++ b/ambari-admin/src/main/resources/ui/admin-web/app/views/ambariViews/edit.html @@ -107,41 +107,6 @@ </div> </div> -<div class="panel panel-default views-permissions-panel" style=""> - <div class="panel-heading clearfix"> - <h3 class="panel-title pull-left">{{'views.permissions' | translate}}</h3> - </div> - <div class="panel-body"> - - - <table class="table" ng-show="!isPermissionsEmpty"> - <thead> - <tr> - <th class="col-sm-2"><label>{{'views.permission' | translate}}</label></th> - <th><label>{{'views.grantUsers' | translate}}</label></th> - <th><label>{{'views.grantGroups' | translate}}</label></th> - </tr> - </thead> - <tbody> - <tr ng-repeat="permission in permissions"> - <td> - <label class="" tooltip="{{permission.PermissionInfo.permission_name}}">{{permission.PermissionInfo.permission_name | translate}}</label> - </td> - <td> - <editable-list items-source="permissionsEdit[permission.PermissionInfo.permission_name].USER" editable="true" resource-type="User"></editable-list> - </td> - <td> - <editable-list items-source="permissionsEdit[permission.PermissionInfo.permission_name].GROUP" editable="true" resource-type="Group" ></editable-list> - </td> - </tr> - </tbody> - </table> - <div ng-show="isPermissionsEmpty"> - <div class="alert alert-info">{{'views.alerts.notDefined' | translate: '{term: constants.perms}'}}</div> - </div> - </div> -</div> - <div class="panel panel-default" ng-cloak ng-hide="isSettingsEmpty && instance"> <div class="panel-heading clearfix"> <h3 class="panel-title pull-left">{{'views.settings' | translate}}</h3> @@ -251,3 +216,53 @@ </div> </div> </div> + +<div class="panel panel-default views-permissions-panel" style=""> + <div class="panel-heading clearfix"> + <h3 class="panel-title pull-left">{{'views.permissions' | translate}}</h3> + </div> + <div class="panel-body"> + + + <table class="table" ng-show="!isPermissionsEmpty"> + <thead> + <tr> + <th class="col-sm-2"><label>{{'views.permission' | translate}}</label></th> + <th><label>{{'views.grantUsers' | translate}}</label></th> + <th><label>{{'views.grantGroups' | translate}}</label></th> + </tr> + </thead> + <tbody> + <tr ng-repeat="permission in permissions"> + <td> + <label class="" tooltip="{{permission.PermissionInfo.permission_name}}">{{permission.PermissionInfo.permission_name | translate}}</label> + </td> + <td> + <editable-list items-source="permissionsEdit[permission.PermissionInfo.permission_name].USER" editable="true" resource-type="User"></editable-list> + </td> + <td> + <editable-list items-source="permissionsEdit[permission.PermissionInfo.permission_name].GROUP" editable="true" resource-type="Group" ></editable-list> + </td> + </tr> + </tbody> + </table> + <div ng-show="!isPermissionsEmpty && isLocalCluster && editConfigurationDisabled"> + <div class="col-sm-12 cluster-inherited-permission"> + <strong>{{'views.clusterPermissions.label' | translate}}</strong> + </div> + <div class="col-sm-offset-3 col-sm-9"> + <div class="checkbox col-sm-4" ng-repeat="key in clusterInheritedPermissionKeys"> + <div ng-init="i18nKey = 'views.clusterPermissions.' + key.split('.').join('').toLowerCase()"> + <label> + <input type="checkbox" ng-model="permissionsEdit['VIEW.USER'][key]"> {{i18nKey | translate}} + </label> + </div> + </div> + </div> + + </div> + <div ng-show="isPermissionsEmpty"> + <div class="alert alert-info">{{'views.alerts.notDefined' | translate: '{term: constants.perms}'}}</div> + </div> + </div> +</div> http://git-wip-us.apache.org/repos/asf/ambari/blob/4342a6b7/ambari-server/src/main/java/org/apache/ambari/server/controller/AmbariServer.java ---------------------------------------------------------------------- diff --git a/ambari-server/src/main/java/org/apache/ambari/server/controller/AmbariServer.java b/ambari-server/src/main/java/org/apache/ambari/server/controller/AmbariServer.java index 5c9004b..8476ec6 100644 --- a/ambari-server/src/main/java/org/apache/ambari/server/controller/AmbariServer.java +++ b/ambari-server/src/main/java/org/apache/ambari/server/controller/AmbariServer.java @@ -902,7 +902,7 @@ public class AmbariServer { injector.getInstance(GroupDAO.class), injector.getInstance(PrincipalDAO.class), injector.getInstance(PermissionDAO.class), injector.getInstance(ResourceDAO.class)); UserPrivilegeResourceProvider.init(injector.getInstance(UserDAO.class), injector.getInstance(ClusterDAO.class), - injector.getInstance(GroupDAO.class), injector.getInstance(ViewInstanceDAO.class)); + injector.getInstance(GroupDAO.class), injector.getInstance(ViewInstanceDAO.class), injector.getInstance(PrivilegeDAO.class)); ClusterPrivilegeResourceProvider.init(injector.getInstance(ClusterDAO.class)); AmbariPrivilegeResourceProvider.init(injector.getInstance(ClusterDAO.class)); ActionManager.setTopologyManager(injector.getInstance(TopologyManager.class)); http://git-wip-us.apache.org/repos/asf/ambari/blob/4342a6b7/ambari-server/src/main/java/org/apache/ambari/server/controller/ControllerModule.java ---------------------------------------------------------------------- diff --git a/ambari-server/src/main/java/org/apache/ambari/server/controller/ControllerModule.java b/ambari-server/src/main/java/org/apache/ambari/server/controller/ControllerModule.java index bb2a374..992f2d2 100644 --- a/ambari-server/src/main/java/org/apache/ambari/server/controller/ControllerModule.java +++ b/ambari-server/src/main/java/org/apache/ambari/server/controller/ControllerModule.java @@ -86,6 +86,7 @@ import org.apache.ambari.server.scheduler.ExecutionSchedulerImpl; import org.apache.ambari.server.security.AmbariEntryPoint; import org.apache.ambari.server.security.SecurityHelper; import org.apache.ambari.server.security.SecurityHelperImpl; +import org.apache.ambari.server.security.authorization.AuthorizationHelper; import org.apache.ambari.server.security.encryption.CredentialStoreService; import org.apache.ambari.server.security.encryption.CredentialStoreServiceImpl; import org.apache.ambari.server.serveraction.kerberos.KerberosOperationHandlerFactory; @@ -368,6 +369,7 @@ public class ControllerModule extends AbstractModule { requestStaticInjection(DatabaseChecker.class); requestStaticInjection(KerberosChecker.class); + requestStaticInjection(AuthorizationHelper.class); bindByAnnotation(null); bindNotificationDispatchers(); http://git-wip-us.apache.org/repos/asf/ambari/blob/4342a6b7/ambari-server/src/main/java/org/apache/ambari/server/controller/internal/GroupPrivilegeResourceProvider.java ---------------------------------------------------------------------- diff --git a/ambari-server/src/main/java/org/apache/ambari/server/controller/internal/GroupPrivilegeResourceProvider.java b/ambari-server/src/main/java/org/apache/ambari/server/controller/internal/GroupPrivilegeResourceProvider.java index c853514..94d1cad 100644 --- a/ambari-server/src/main/java/org/apache/ambari/server/controller/internal/GroupPrivilegeResourceProvider.java +++ b/ambari-server/src/main/java/org/apache/ambari/server/controller/internal/GroupPrivilegeResourceProvider.java @@ -28,6 +28,7 @@ import org.apache.ambari.server.controller.spi.SystemException; import org.apache.ambari.server.controller.spi.UnsupportedPropertyException; import org.apache.ambari.server.orm.dao.ClusterDAO; import org.apache.ambari.server.orm.dao.GroupDAO; +import org.apache.ambari.server.orm.dao.PrivilegeDAO; import org.apache.ambari.server.orm.dao.ViewInstanceDAO; import org.apache.ambari.server.orm.entities.ClusterEntity; import org.apache.ambari.server.orm.entities.GroupEntity; @@ -35,10 +36,7 @@ import org.apache.ambari.server.orm.entities.PrincipalTypeEntity; import org.apache.ambari.server.orm.entities.PrivilegeEntity; import org.apache.ambari.server.orm.entities.ViewEntity; import org.apache.ambari.server.orm.entities.ViewInstanceEntity; -import org.apache.ambari.server.security.authorization.AuthorizationException; -import org.apache.ambari.server.security.authorization.AuthorizationHelper; -import org.apache.ambari.server.security.authorization.ResourceType; -import org.apache.ambari.server.security.authorization.RoleAuthorization; +import org.apache.ambari.server.security.authorization.*; import java.util.EnumSet; import java.util.HashMap; @@ -83,6 +81,12 @@ public class GroupPrivilegeResourceProvider extends ReadOnlyResourceProvider { protected static ViewInstanceDAO viewInstanceDAO; /** + * Data access object used to obtain privilege entities. + */ + @Inject + protected static PrivilegeDAO privilegeDAO; + + /** * The property ids for a privilege resource. */ private static Set<String> propertyIds = new HashSet<String>(); @@ -103,16 +107,17 @@ public class GroupPrivilegeResourceProvider extends ReadOnlyResourceProvider { /** * Static initialization. - * - * @param clusterDAO the cluster data access object + * @param clusterDAO the cluster data access object * @param groupDAO the group data access object * @param viewInstanceDAO the view instance data access object + * @param privilegeDAO */ public static void init(ClusterDAO clusterDAO, GroupDAO groupDAO, - ViewInstanceDAO viewInstanceDAO) { + ViewInstanceDAO viewInstanceDAO, PrivilegeDAO privilegeDAO) { GroupPrivilegeResourceProvider.clusterDAO = clusterDAO; GroupPrivilegeResourceProvider.groupDAO = groupDAO; GroupPrivilegeResourceProvider.viewInstanceDAO = viewInstanceDAO; + GroupPrivilegeResourceProvider.privilegeDAO = privilegeDAO; } @SuppressWarnings("serial") @@ -176,6 +181,11 @@ public class GroupPrivilegeResourceProvider extends ReadOnlyResourceProvider { } final Set<PrivilegeEntity> privileges = groupEntity.getPrincipal().getPrivileges(); + + Set<PrivilegeEntity> allViewPrivilegesWithClusterPermission = + ClusterInheritedPermissionHelper.getViewPrivilegesWithClusterPermission(viewInstanceDAO, privilegeDAO, privileges); + privileges.addAll(allViewPrivilegesWithClusterPermission); + for (PrivilegeEntity privilegeEntity : privileges) { resources.add(toResource(privilegeEntity, groupName, requestedIds)); } http://git-wip-us.apache.org/repos/asf/ambari/blob/4342a6b7/ambari-server/src/main/java/org/apache/ambari/server/controller/internal/PrivilegeResourceProvider.java ---------------------------------------------------------------------- diff --git a/ambari-server/src/main/java/org/apache/ambari/server/controller/internal/PrivilegeResourceProvider.java b/ambari-server/src/main/java/org/apache/ambari/server/controller/internal/PrivilegeResourceProvider.java index c825dc9..34111df 100644 --- a/ambari-server/src/main/java/org/apache/ambari/server/controller/internal/PrivilegeResourceProvider.java +++ b/ambari-server/src/main/java/org/apache/ambari/server/controller/internal/PrivilegeResourceProvider.java @@ -51,6 +51,7 @@ import org.apache.ambari.server.orm.entities.PrincipalTypeEntity; import org.apache.ambari.server.orm.entities.PrivilegeEntity; import org.apache.ambari.server.orm.entities.ResourceEntity; import org.apache.ambari.server.orm.entities.UserEntity; +import org.apache.ambari.server.security.authorization.ClusterInheritedPermissionHelper; /** * Abstract resource provider for privilege resources. @@ -348,6 +349,8 @@ public abstract class PrivilegeResourceProvider<T> extends AbstractAuthorizedRes if (userEntity != null) { entity.setPrincipal(principalDAO.findById(userEntity.getPrincipal().getId())); } + } else if (ClusterInheritedPermissionHelper.isValidPrincipalType(principalType)) { + entity.setPrincipal(principalDAO.findByPrincipalType(principalType).get(0)); // There will be only one principal for that type } else { throw new AmbariException("Unknown principal type " + principalType); } http://git-wip-us.apache.org/repos/asf/ambari/blob/4342a6b7/ambari-server/src/main/java/org/apache/ambari/server/controller/internal/UserPrivilegeResourceProvider.java ---------------------------------------------------------------------- diff --git a/ambari-server/src/main/java/org/apache/ambari/server/controller/internal/UserPrivilegeResourceProvider.java b/ambari-server/src/main/java/org/apache/ambari/server/controller/internal/UserPrivilegeResourceProvider.java index cef8a11..bdd73a6 100644 --- a/ambari-server/src/main/java/org/apache/ambari/server/controller/internal/UserPrivilegeResourceProvider.java +++ b/ambari-server/src/main/java/org/apache/ambari/server/controller/internal/UserPrivilegeResourceProvider.java @@ -17,12 +17,8 @@ */ package org.apache.ambari.server.controller.internal; -import java.util.EnumSet; -import java.util.HashMap; -import java.util.HashSet; -import java.util.Map; -import java.util.Set; - +import com.google.common.base.Function; +import com.google.common.collect.FluentIterable; import org.apache.ambari.server.controller.spi.NoSuchParentResourceException; import org.apache.ambari.server.controller.spi.NoSuchResourceException; import org.apache.ambari.server.controller.spi.Predicate; @@ -32,6 +28,7 @@ import org.apache.ambari.server.controller.spi.SystemException; import org.apache.ambari.server.controller.spi.UnsupportedPropertyException; import org.apache.ambari.server.orm.dao.ClusterDAO; import org.apache.ambari.server.orm.dao.GroupDAO; +import org.apache.ambari.server.orm.dao.PrivilegeDAO; import org.apache.ambari.server.orm.dao.UserDAO; import org.apache.ambari.server.orm.dao.ViewInstanceDAO; import org.apache.ambari.server.orm.entities.ClusterEntity; @@ -39,15 +36,24 @@ import org.apache.ambari.server.orm.entities.GroupEntity; import org.apache.ambari.server.orm.entities.MemberEntity; import org.apache.ambari.server.orm.entities.PrincipalTypeEntity; import org.apache.ambari.server.orm.entities.PrivilegeEntity; +import org.apache.ambari.server.orm.entities.ResourceEntity; import org.apache.ambari.server.orm.entities.UserEntity; import org.apache.ambari.server.orm.entities.ViewEntity; import org.apache.ambari.server.orm.entities.ViewInstanceEntity; import org.apache.ambari.server.security.authorization.AuthorizationException; import org.apache.ambari.server.security.authorization.AuthorizationHelper; +import org.apache.ambari.server.security.authorization.ClusterInheritedPermissionHelper; import org.apache.ambari.server.security.authorization.ResourceType; import org.apache.ambari.server.security.authorization.RoleAuthorization; import org.apache.ambari.server.security.authorization.UserType; +import javax.annotation.Nullable; +import java.util.EnumSet; +import java.util.HashMap; +import java.util.HashSet; +import java.util.Map; +import java.util.Set; + /** * Resource provider for user privilege resources. */ @@ -86,6 +92,11 @@ public class UserPrivilegeResourceProvider extends ReadOnlyResourceProvider { protected static ViewInstanceDAO viewInstanceDAO; /** + * DAO used to obtain privilege entities. + */ + protected static PrivilegeDAO privilegeDAO; + + /** * The property ids for a privilege resource. */ private static Set<String> propertyIds = new HashSet<String>(); @@ -105,18 +116,19 @@ public class UserPrivilegeResourceProvider extends ReadOnlyResourceProvider { /** * Static initialization. - * - * @param userDAO the user data access object + * @param userDAO the user data access object * @param clusterDAO the cluster data access object * @param groupDAO the group data access object * @param viewInstanceDAO the view instance data access object + * @param privilegeDAO */ public static void init(UserDAO userDAO, ClusterDAO clusterDAO, GroupDAO groupDAO, - ViewInstanceDAO viewInstanceDAO) { + ViewInstanceDAO viewInstanceDAO, PrivilegeDAO privilegeDAO) { UserPrivilegeResourceProvider.userDAO = userDAO; UserPrivilegeResourceProvider.clusterDAO = clusterDAO; UserPrivilegeResourceProvider.groupDAO = groupDAO; UserPrivilegeResourceProvider.viewInstanceDAO = viewInstanceDAO; + UserPrivilegeResourceProvider.privilegeDAO = privilegeDAO; } @SuppressWarnings("serial") @@ -163,6 +175,7 @@ public class UserPrivilegeResourceProvider extends ReadOnlyResourceProvider { final Set<Resource> resources = new HashSet<Resource>(); final Set<String> requestedIds = getRequestPropertyIds(request, predicate); + boolean isUserAdministrator = AuthorizationHelper.isAuthorized(ResourceType.AMBARI, null, RoleAuthorization.AMBARI_MANAGE_USERS); @@ -187,10 +200,15 @@ public class UserPrivilegeResourceProvider extends ReadOnlyResourceProvider { } final Set<PrivilegeEntity> privileges = userEntity.getPrincipal().getPrivileges(); + for (MemberEntity membership : userEntity.getMemberEntities()) { privileges.addAll(membership.getGroup().getPrincipal().getPrivileges()); } + Set<PrivilegeEntity> allViewPrivilegesWithClusterPermission = + ClusterInheritedPermissionHelper.getViewPrivilegesWithClusterPermission(viewInstanceDAO, privilegeDAO, privileges); + privileges.addAll(allViewPrivilegesWithClusterPermission); + for (PrivilegeEntity privilegeEntity : privileges) { resources.add(toResource(privilegeEntity, userName, requestedIds)); } @@ -199,6 +217,7 @@ public class UserPrivilegeResourceProvider extends ReadOnlyResourceProvider { return resources; } + /** * Translate the found data into a Resource * http://git-wip-us.apache.org/repos/asf/ambari/blob/4342a6b7/ambari-server/src/main/java/org/apache/ambari/server/orm/dao/PrincipalDAO.java ---------------------------------------------------------------------- diff --git a/ambari-server/src/main/java/org/apache/ambari/server/orm/dao/PrincipalDAO.java b/ambari-server/src/main/java/org/apache/ambari/server/orm/dao/PrincipalDAO.java index 3d09227..efbdfab 100644 --- a/ambari-server/src/main/java/org/apache/ambari/server/orm/dao/PrincipalDAO.java +++ b/ambari-server/src/main/java/org/apache/ambari/server/orm/dao/PrincipalDAO.java @@ -80,6 +80,14 @@ public class PrincipalDAO { return daoUtils.selectList(query); } + + @RequiresSession + public List<PrincipalEntity> findByPrincipalType(String name) { + TypedQuery<PrincipalEntity> query = entityManagerProvider.get().createNamedQuery("principalByPrincipalType", PrincipalEntity.class); + query.setParameter("principal_type", name); + return daoUtils.selectList(query); + } + /** * Make an instance managed and persistent. * http://git-wip-us.apache.org/repos/asf/ambari/blob/4342a6b7/ambari-server/src/main/java/org/apache/ambari/server/orm/entities/PrincipalEntity.java ---------------------------------------------------------------------- diff --git a/ambari-server/src/main/java/org/apache/ambari/server/orm/entities/PrincipalEntity.java b/ambari-server/src/main/java/org/apache/ambari/server/orm/entities/PrincipalEntity.java index 601a7d1..25d8d14 100644 --- a/ambari-server/src/main/java/org/apache/ambari/server/orm/entities/PrincipalEntity.java +++ b/ambari-server/src/main/java/org/apache/ambari/server/orm/entities/PrincipalEntity.java @@ -47,7 +47,8 @@ import javax.persistence.TableGenerator; , allocationSize = 500 ) @NamedQueries({ - @NamedQuery(name = "principalByPrivilegeId", query = "SELECT principal FROM PrincipalEntity principal JOIN principal.privileges privilege WHERE privilege.permission.id=:permission_id") + @NamedQuery(name = "principalByPrivilegeId", query = "SELECT principal FROM PrincipalEntity principal JOIN principal.privileges privilege WHERE privilege.permission.id=:permission_id"), + @NamedQuery(name = "principalByPrincipalType", query = "SELECT principal FROM PrincipalEntity principal WHERE principal.principalType.name = :principal_type") }) public class PrincipalEntity { http://git-wip-us.apache.org/repos/asf/ambari/blob/4342a6b7/ambari-server/src/main/java/org/apache/ambari/server/orm/entities/PrincipalTypeEntity.java ---------------------------------------------------------------------- diff --git a/ambari-server/src/main/java/org/apache/ambari/server/orm/entities/PrincipalTypeEntity.java b/ambari-server/src/main/java/org/apache/ambari/server/orm/entities/PrincipalTypeEntity.java index f05a643..b94f1ff 100644 --- a/ambari-server/src/main/java/org/apache/ambari/server/orm/entities/PrincipalTypeEntity.java +++ b/ambari-server/src/main/java/org/apache/ambari/server/orm/entities/PrincipalTypeEntity.java @@ -37,9 +37,19 @@ public class PrincipalTypeEntity { */ public static final int USER_PRINCIPAL_TYPE = 1; public static final int GROUP_PRINCIPAL_TYPE = 2; + public static final int CLUSTER_ADMINISTRATOR_PRINCIPAL_TYPE = 3; + public static final int CLUSTER_OPERATOR_PRINCIPAL_TYPE = 4; + public static final int CLUSTER_USER_PRINCIPAL_TYPE = 5; + public static final int SERVICE_ADMINISTRATOR_PRINCIPAL_TYPE = 6; + public static final int SERVICE_OPERATOR_PRINCIPAL_TYPE = 7; public static final String USER_PRINCIPAL_TYPE_NAME = "USER"; public static final String GROUP_PRINCIPAL_TYPE_NAME = "GROUP"; + public static final String CLUSTER_ADMINISTRATOR_PRINCIPAL_TYPE_NAME = "ALL.CLUSTER.ADMINISTRATOR"; + public static final String CLUSTER_OPERATOR_PRINCIPAL_TYPE_NAME = "ALL.CLUSTER.OPERATOR"; + public static final String CLUSTER_USER_PRINCIPAL_TYPE_NAME = "ALL.CLUSTER.USER"; + public static final String SERVICE_ADMINISTRATOR_PRINCIPAL_TYPE_NAME = "ALL.SERVICE.ADMINISTRATOR"; + public static final String SERVICE_OPERATOR_PRINCIPAL_TYPE_NAME = "ALL.SERVICE.OPERATOR"; /** * The type id. http://git-wip-us.apache.org/repos/asf/ambari/blob/4342a6b7/ambari-server/src/main/java/org/apache/ambari/server/security/authorization/AuthorizationHelper.java ---------------------------------------------------------------------- diff --git a/ambari-server/src/main/java/org/apache/ambari/server/security/authorization/AuthorizationHelper.java b/ambari-server/src/main/java/org/apache/ambari/server/security/authorization/AuthorizationHelper.java index 4007c76..f9f0611 100644 --- a/ambari-server/src/main/java/org/apache/ambari/server/security/authorization/AuthorizationHelper.java +++ b/ambari-server/src/main/java/org/apache/ambari/server/security/authorization/AuthorizationHelper.java @@ -17,17 +17,20 @@ */ package org.apache.ambari.server.security.authorization; +import com.google.common.base.Function; +import com.google.common.base.Predicate; +import com.google.common.collect.FluentIterable; import com.google.common.collect.Lists; +import com.google.inject.Inject; +import com.google.inject.Provider; import com.google.inject.Singleton; - -import org.apache.ambari.server.AmbariException; -import org.apache.ambari.server.orm.dao.ClusterDAO; +import org.apache.ambari.server.orm.dao.PrivilegeDAO; import org.apache.ambari.server.orm.dao.ViewInstanceDAO; import org.apache.ambari.server.orm.entities.PermissionEntity; import org.apache.ambari.server.orm.entities.PrivilegeEntity; import org.apache.ambari.server.orm.entities.ResourceEntity; import org.apache.ambari.server.orm.entities.RoleAuthorizationEntity; -import org.apache.ambari.server.state.Clusters; +import org.apache.ambari.server.orm.entities.ViewInstanceEntity; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.security.core.Authentication; @@ -38,7 +41,11 @@ import org.springframework.web.context.request.RequestAttributes; import org.springframework.web.context.request.RequestContextHolder; import org.springframework.web.context.request.ServletRequestAttributes; -import java.util.*; +import java.util.Collection; +import java.util.EnumSet; +import java.util.HashSet; +import java.util.List; +import java.util.Set; @Singleton /** @@ -47,6 +54,12 @@ import java.util.*; public class AuthorizationHelper { private final static Logger LOG = LoggerFactory.getLogger(AuthorizationHelper.class); + @Inject + static Provider<PrivilegeDAO> privilegeDAOProvider; + + @Inject + static Provider<ViewInstanceDAO> viewInstanceDAOProvider; + /** * Converts collection of RoleEntities to collection of GrantedAuthorities */ @@ -197,8 +210,56 @@ public class AuthorizationHelper { } } - return false; + // Check if the resourceId is a view. + // Get all privileges for the resourceId and the principal associated for them should be of all cluster/service + // type. + // Now from the authorities check if the user privileges with CLUSTER/SERVICE type permission and has access to + // cluster resource with the permission. + // Then if the permission type matches the cluster/service type principal(names) then the user should have access + // to those views. + + if(resourceId == null) { + return false; + } + + ViewInstanceDAO viewInstanceDAO = viewInstanceDAOProvider.get(); + + ViewInstanceEntity instanceEntity = viewInstanceDAO.findByResourceId(resourceId); + if(instanceEntity == null || instanceEntity.getClusterHandle() == null) { + return false; + } + + PrivilegeDAO privilegeDAO = privilegeDAOProvider.get(); + + final Set<String> privilegeNames = FluentIterable.from(privilegeDAO.findByResourceId(resourceId)) + .filter(ClusterInheritedPermissionHelper.privilegeWithClusterInheritedPermissionTypePredicate) + .transform(ClusterInheritedPermissionHelper.permissionNameFromClusterInheritedPrivilege) + .toSet(); + + return FluentIterable.from(authentication.getAuthorities()) + .filter(new Predicate<GrantedAuthority>() { + @Override + public boolean apply(GrantedAuthority grantedAuthority) { + AmbariGrantedAuthority authority = (AmbariGrantedAuthority) grantedAuthority; + PrivilegeEntity privilege = authority.getPrivilegeEntity(); + String resourceTypeName = privilege.getResource().getResourceType().getName(); + return ResourceType.translate(resourceTypeName) == ResourceType.CLUSTER; + } + }).transform(new Function<GrantedAuthority, PermissionEntity>() { + @Override + public PermissionEntity apply(GrantedAuthority grantedAuthority) { + AmbariGrantedAuthority authority = (AmbariGrantedAuthority) grantedAuthority; + PrivilegeEntity privilege = authority.getPrivilegeEntity(); + return privilege.getPermission(); + } + }).anyMatch(new Predicate<PermissionEntity>() { + @Override + public boolean apply(PermissionEntity input) { + return privilegeNames.contains(input.getPermissionName()); + } + }); } + } /** http://git-wip-us.apache.org/repos/asf/ambari/blob/4342a6b7/ambari-server/src/main/java/org/apache/ambari/server/security/authorization/ClusterInheritedPermissionHelper.java ---------------------------------------------------------------------- diff --git a/ambari-server/src/main/java/org/apache/ambari/server/security/authorization/ClusterInheritedPermissionHelper.java b/ambari-server/src/main/java/org/apache/ambari/server/security/authorization/ClusterInheritedPermissionHelper.java new file mode 100644 index 0000000..9922bb2 --- /dev/null +++ b/ambari-server/src/main/java/org/apache/ambari/server/security/authorization/ClusterInheritedPermissionHelper.java @@ -0,0 +1,213 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.ambari.server.security.authorization; + +import com.google.common.base.Function; +import com.google.common.base.Predicate; +import com.google.common.collect.FluentIterable; +import org.apache.ambari.server.orm.dao.PrivilegeDAO; +import org.apache.ambari.server.orm.dao.ViewInstanceDAO; +import org.apache.ambari.server.orm.entities.PrincipalTypeEntity; +import org.apache.ambari.server.orm.entities.PrivilegeEntity; +import org.apache.ambari.server.orm.entities.ResourceEntity; +import org.apache.ambari.server.orm.entities.ViewInstanceEntity; + +import javax.annotation.Nullable; +import java.util.Collection; +import java.util.Set; + + +/** + * Helper class to take care of the cluster inherited permission for any view. + */ +public class ClusterInheritedPermissionHelper { + + /** + * Predicate which validates if the principalType passed is valid or not. + */ + public static final Predicate<String> validPrincipalTypePredicate = new Predicate<String>() { + @Override + public boolean apply(String principalType) { + return isValidPrincipalType(principalType); + } + }; + + /** + * Predicate which validates if the privilegeEntity has resourceEntity of type {@see ResourceType.CLUSTER} + */ + public static final Predicate<PrivilegeEntity> clusterPrivilegesPredicate = new Predicate<PrivilegeEntity>() { + @Override + public boolean apply(PrivilegeEntity privilegeEntity) { + String resourceTypeName = privilegeEntity.getResource().getResourceType().getName(); + return ResourceType.translate(resourceTypeName) == ResourceType.CLUSTER; + } + }; + + /** + * Predicate which validates if view instance entity is cluster associated + */ + public static final Predicate<ViewInstanceEntity> clusterAssociatedViewInstancePredicate = new Predicate<ViewInstanceEntity>() { + @Override + public boolean apply(ViewInstanceEntity viewInstanceEntity) { + return viewInstanceEntity.getClusterHandle() != null; + } + }; + + /** + * Predicate to validate if the privilege entity has a principal which has a cluster inherited principal type + */ + public static final Predicate<PrivilegeEntity> privilegeWithClusterInheritedPermissionTypePredicate = new Predicate<PrivilegeEntity>() { + @Override + public boolean apply(PrivilegeEntity privilegeEntity) { + String principalTypeName = privilegeEntity.getPrincipal().getPrincipalType().getName(); + return principalTypeName.startsWith("ALL."); + } + }; + + /** + * Mapper to return the Permission Name from the cluster inherited privilege name. Example: "ALL.CLUSTER.USER" becomes "CLUSTER.USER" + */ + public static final Function<PrivilegeEntity, String> permissionNameFromClusterInheritedPrivilege = new Function<PrivilegeEntity, String>() { + @Override + public String apply(PrivilegeEntity input) { + return input.getPrincipal().getPrincipalType().getName().substring(4); + } + }; + + /** + * Mapper to return resources from view instance entity. + */ + public static final Function<ViewInstanceEntity, ResourceEntity> resourceFromViewInstanceMapper = new Function<ViewInstanceEntity, ResourceEntity>() { + @Override + public ResourceEntity apply(ViewInstanceEntity viewInstanceEntity) { + return viewInstanceEntity.getResource(); + } + }; + + /** + * Mapper to return all privileges from resource entity + */ + public static final Function<ResourceEntity, Iterable<PrivilegeEntity>> allPrivilegesFromResoucesMapper = new Function<ResourceEntity, Iterable<PrivilegeEntity>>() { + @Override + public Iterable<PrivilegeEntity> apply(ResourceEntity resourceEntity) { + return resourceEntity.getPrivileges(); + } + }; + + /** + * Mapper to return permission name from privilege + */ + public static final Function<PrivilegeEntity, String> permissionNameFromPrivilegeMapper = new Function<PrivilegeEntity, String>() { + @Override + public String apply(PrivilegeEntity privilegeEntity) { + return privilegeEntity.getPermission().getPermissionName(); + } + }; + + /** + * Predicate to validate if the cluster inherited principal type for privilege entity is present in the valid permission type set passed + * @param validSet - valid set of permission types + * @return Predicate to check the condition + */ + public static final Predicate<PrivilegeEntity> principalTypeInSetFrom(final Collection<String> validSet) { + return new Predicate<PrivilegeEntity>() { + @Override + public boolean apply(PrivilegeEntity privilegeEntity) { + String permissionName = privilegeEntity.getPrincipal().getPrincipalType().getName().substring(4); + return validSet.contains(permissionName); + } + }; + } + + /** + * Predicate to filter out privileges which are already existing in the passed privileges set. + * @param existingPrivileges - Privileges set to which the comparison will be made + * @return Predicate to check the validation + */ + public static Predicate<PrivilegeEntity> removeIfExistingPrivilegePredicate(final Set<PrivilegeEntity> existingPrivileges) { + return new Predicate<PrivilegeEntity>() { + @Override + public boolean apply(final PrivilegeEntity privilegeEntity) { + return !FluentIterable.from(existingPrivileges).anyMatch(new com.google.common.base.Predicate<PrivilegeEntity>() { + @Override + public boolean apply(PrivilegeEntity directPrivilegeEntity) { + return directPrivilegeEntity.getResource().getId().equals(privilegeEntity.getResource().getId()) + && directPrivilegeEntity.getPermission().getId().equals(privilegeEntity.getPermission().getId()); + } + }); + } + }; + } + + /** + * Validates if the principal type is valid for cluster inherited permissions. + * @param principalType - Principal type + * @return true if the principalType is in ("ALL.CLUSTER.ADMINISTRATOR", "ALL.CLUSTER.OPERATOR", + * "ALL.CLUSTER.USER", "ALL.SERVICE.OPERATOR", "ALL.SERVICE.USER") + */ + public static boolean isValidPrincipalType(String principalType) { + return PrincipalTypeEntity.CLUSTER_ADMINISTRATOR_PRINCIPAL_TYPE_NAME.equalsIgnoreCase(principalType) + || PrincipalTypeEntity.CLUSTER_OPERATOR_PRINCIPAL_TYPE_NAME.equalsIgnoreCase(principalType) + || PrincipalTypeEntity.CLUSTER_USER_PRINCIPAL_TYPE_NAME.equalsIgnoreCase(principalType) + || PrincipalTypeEntity.SERVICE_ADMINISTRATOR_PRINCIPAL_TYPE_NAME.equalsIgnoreCase(principalType) + || PrincipalTypeEntity.SERVICE_OPERATOR_PRINCIPAL_TYPE_NAME.equalsIgnoreCase(principalType); + } + + /** + * Returns the view privileges for which cluster permissions has been specified. This filters out all the privileges + * which are related to view resources attached to a cluster and are configured to have cluster level permissions. Then + * It checks if the user has cluster level permissions and further filters down the privilege list to the ones for which + * the user should have privilege. + * @param userDirectPrivileges - direct privileges for the user. + * @return - Filtered list of privileges for view resource for which the user should have access. + */ + public static Set<PrivilegeEntity> getViewPrivilegesWithClusterPermission(final ViewInstanceDAO viewInstanceDAO, final PrivilegeDAO privilegeDAO, + final Set<PrivilegeEntity> userDirectPrivileges) { + + final Set<String> clusterPrivileges = FluentIterable.from(userDirectPrivileges) + .filter(ClusterInheritedPermissionHelper.clusterPrivilegesPredicate) + .transform(ClusterInheritedPermissionHelper.permissionNameFromPrivilegeMapper) + .toSet(); + + Set<Long> resourceIds = FluentIterable.from(viewInstanceDAO.findAll()) + .filter(ClusterInheritedPermissionHelper.clusterAssociatedViewInstancePredicate) + .transform(ClusterInheritedPermissionHelper.resourceFromViewInstanceMapper) + .transform(new Function<ResourceEntity, Long>() { + @Nullable + @Override + public Long apply(@Nullable ResourceEntity input) { + return input.getId(); + } + }).toSet(); + + Set<PrivilegeEntity> allPrivileges = FluentIterable.from(resourceIds) + .transformAndConcat(new Function<Long, Iterable<PrivilegeEntity>>() { + @Nullable + @Override + public Iterable<PrivilegeEntity> apply(@Nullable Long input) { + return privilegeDAO.findByResourceId(input); + } + }).toSet(); + + return FluentIterable.from(allPrivileges) + .filter(ClusterInheritedPermissionHelper.privilegeWithClusterInheritedPermissionTypePredicate) + .filter(ClusterInheritedPermissionHelper.principalTypeInSetFrom(clusterPrivileges)) + .filter(ClusterInheritedPermissionHelper.removeIfExistingPrivilegePredicate(userDirectPrivileges)) + .toSet(); + } +} http://git-wip-us.apache.org/repos/asf/ambari/blob/4342a6b7/ambari-server/src/main/java/org/apache/ambari/server/upgrade/AbstractUpgradeCatalog.java ---------------------------------------------------------------------- diff --git a/ambari-server/src/main/java/org/apache/ambari/server/upgrade/AbstractUpgradeCatalog.java b/ambari-server/src/main/java/org/apache/ambari/server/upgrade/AbstractUpgradeCatalog.java index 2e857ed..1212d6e 100644 --- a/ambari-server/src/main/java/org/apache/ambari/server/upgrade/AbstractUpgradeCatalog.java +++ b/ambari-server/src/main/java/org/apache/ambari/server/upgrade/AbstractUpgradeCatalog.java @@ -155,6 +155,42 @@ public abstract class AbstractUpgradeCatalog implements UpgradeCatalog { } /** + * Get a sequence value and increment it in <code>ambariSequencesTable</code>. + * @param seqName name of sequence to be fetched and incremented + * @throws SQLException, IllegalArgumentException + */ + @Transactional + public int getAndIncrementSequence(String seqName) throws SQLException{ + Statement statement = null; + ResultSet rs = null; + int value = -1; + try { + statement = dbAccessor.getConnection().createStatement(); + if (statement != null) { + rs = statement.executeQuery(String.format("SELECT COUNT(*) from %s where sequence_name='%s'", ambariSequencesTable, seqName)); + + if(rs != null) { + value = rs.getInt(1); + dbAccessor.executeUpdate(String.format("UPDATE %s SET sequence_value = sequence_value + 1 where sequence_name='%s'", ambariSequencesTable, seqName)); + } else { + LOG.error("Sequence {} not found.", seqName); + throw new IllegalArgumentException("Sequence " + seqName + " not found."); + } + + } + } finally { + if (rs != null) { + rs.close(); + } + if (statement != null) { + statement.close(); + } + } + + return value; + } + + /** * Add several new sequences to <code>ambariSequencesTable</code>. * @param seqNames list of sequences to be inserted * @param seqDefaultValue initial value for the sequence http://git-wip-us.apache.org/repos/asf/ambari/blob/4342a6b7/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 b9b14be..dc8d9b7 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 @@ -110,6 +110,8 @@ public class UpgradeCatalog240 extends AbstractUpgradeCatalog { public static final String TIMELINE_METRICS_SINK_COLLECTION_PERIOD = "timeline.metrics.sink.collection.period"; public static final String VIEWURL_TABLE = "viewurl"; public static final String URL_ID_COLUMN = "url_id"; + private static final String PRINCIPAL_TYPE_TABLE = "adminprincipaltype"; + private static final String PRINCIPAL_TABLE = "adminprincipal"; @Inject @@ -228,6 +230,31 @@ public class UpgradeCatalog240 extends AbstractUpgradeCatalog { removeHiveOozieDBConnectionConfigs(); updateClustersAndHostsVersionStateTableDML(); removeStandardDeviationAlerts(); + updateClusterInheritedPermissionsConfig(); + } + + protected void updateClusterInheritedPermissionsConfig() throws SQLException { + dbAccessor.insertRow(PRINCIPAL_TYPE_TABLE, new String[]{"principal_type_id", "principal_type_name"}, new String[]{"3", "'ALL.CLUSTER.ADMINISTRATOR'"}, true); + dbAccessor.insertRow(PRINCIPAL_TYPE_TABLE, new String[]{"principal_type_id", "principal_type_name"}, new String[]{"4", "'ALL.CLUSTER.OPERATOR'"}, true); + dbAccessor.insertRow(PRINCIPAL_TYPE_TABLE, new String[]{"principal_type_id", "principal_type_name"}, new String[]{"5", "'ALL.CLUSTER.USER'"}, true); + dbAccessor.insertRow(PRINCIPAL_TYPE_TABLE, new String[]{"principal_type_id", "principal_type_name"}, new String[]{"6", "'ALL.SERVICE.ADMINISTRATOR'"}, true); + dbAccessor.insertRow(PRINCIPAL_TYPE_TABLE, new String[]{"principal_type_id", "principal_type_name"}, new String[]{"7", "'ALL.SERVICE.OPERATOR'"}, true); + getAndIncrementSequence("principal_type_id_seq"); + getAndIncrementSequence("principal_type_id_seq"); + getAndIncrementSequence("principal_type_id_seq"); + getAndIncrementSequence("principal_type_id_seq"); + getAndIncrementSequence("principal_type_id_seq"); + + int nextPrincipalSeqId = getAndIncrementSequence("principal_id_seq"); + dbAccessor.insertRow(PRINCIPAL_TABLE, new String[]{"principal_id", "principal_type_id"}, new String[]{Integer.toString(nextPrincipalSeqId), "3"}, true); + nextPrincipalSeqId = getAndIncrementSequence("principal_id_seq"); + dbAccessor.insertRow(PRINCIPAL_TABLE, new String[]{"principal_id", "principal_type_id"}, new String[]{Integer.toString(nextPrincipalSeqId), "4"}, true); + nextPrincipalSeqId = getAndIncrementSequence("principal_id_seq"); + dbAccessor.insertRow(PRINCIPAL_TABLE, new String[]{"principal_id", "principal_type_id"}, new String[]{Integer.toString(nextPrincipalSeqId), "5"}, true); + nextPrincipalSeqId = getAndIncrementSequence("principal_id_seq"); + dbAccessor.insertRow(PRINCIPAL_TABLE, new String[]{"principal_id", "principal_type_id"}, new String[]{Integer.toString(nextPrincipalSeqId), "6"}, true); + nextPrincipalSeqId = getAndIncrementSequence("principal_id_seq"); + dbAccessor.insertRow(PRINCIPAL_TABLE, new String[]{"principal_id", "principal_type_id"}, new String[]{Integer.toString(nextPrincipalSeqId), "7"}, true); } private void createSettingTable() throws SQLException {