diff --git a/app/docker/views/containers/edit/containerController.js b/app/docker/views/containers/edit/containerController.js index 6528669f1..4a60af2c5 100644 --- a/app/docker/views/containers/edit/containerController.js +++ b/app/docker/views/containers/edit/containerController.js @@ -21,6 +21,7 @@ angular.module('portainer.docker').controller('ContainerController', [ 'ImageService', 'HttpRequestHelper', 'Authentication', + 'StateManager', function ( $q, $scope, @@ -40,7 +41,8 @@ angular.module('portainer.docker').controller('ContainerController', [ RegistryService, ImageService, HttpRequestHelper, - Authentication + Authentication, + StateManager ) { $scope.activityTime = 0; $scope.portBindings = []; @@ -94,9 +96,13 @@ angular.module('portainer.docker').controller('ContainerController', [ const inSwarm = $scope.container.Config.Labels['com.docker.swarm.service.id']; const autoRemove = $scope.container.HostConfig.AutoRemove; const admin = Authentication.isAdmin(); + const appState = StateManager.getState(); + const { allowHostNamespaceForRegularUsers, allowDeviceMappingForRegularUsers, allowBindMountsForRegularUsers, allowPrivilegedModeForRegularUsers } = appState.application; + const settingRestrictsRegularUsers = + !allowBindMountsForRegularUsers || !allowDeviceMappingForRegularUsers || !allowHostNamespaceForRegularUsers || !allowPrivilegedModeForRegularUsers; ExtensionService.extensionEnabled(ExtensionService.EXTENSIONS.RBAC).then((rbacEnabled) => { - $scope.displayRecreateButton = !inSwarm && !autoRemove && (rbacEnabled ? admin : true); + $scope.displayRecreateButton = !inSwarm && !autoRemove && (settingRestrictsRegularUsers || rbacEnabled ? admin : true); }); }) .catch(function error(err) { diff --git a/app/portainer/models/settings.js b/app/portainer/models/settings.js index 840244e5e..1b1e38672 100644 --- a/app/portainer/models/settings.js +++ b/app/portainer/models/settings.js @@ -30,6 +30,7 @@ export function PublicSettingsViewModel(settings) { this.OAuthLoginURI = settings.OAuthLoginURI; this.AllowStackManagementForRegularUsers = settings.AllowStackManagementForRegularUsers; this.AllowDeviceMappingForRegularUsers = settings.AllowDeviceMappingForRegularUsers; + this.AllowHostNamespaceForRegularUsers = settings.AllowHostNamespaceForRegularUsers; } export function LDAPSettingsViewModel(data) { diff --git a/app/portainer/services/stateManager.js b/app/portainer/services/stateManager.js index 1c8792807..66fc15cf7 100644 --- a/app/portainer/services/stateManager.js +++ b/app/portainer/services/stateManager.js @@ -91,6 +91,16 @@ angular.module('portainer.app').factory('StateManager', [ LocalStorage.storeApplicationState(state.application); }; + manager.updateAllowBindMountsForRegularUsers = function updateAllowBindMountsForRegularUsers(allowBindMountsForRegularUsers) { + state.application.allowBindMountsForRegularUsers = allowBindMountsForRegularUsers; + LocalStorage.storeApplicationState(state.application); + }; + + manager.updateAllowPrivilegedModeForRegularUsers = function (AllowPrivilegedModeForRegularUsers) { + state.application.allowPrivilegedModeForRegularUsers = AllowPrivilegedModeForRegularUsers; + LocalStorage.storeApplicationState(state.application); + }; + function assignStateFromStatusAndSettings(status, settings) { state.application.authentication = status.Authentication; state.application.analytics = status.Analytics; @@ -103,7 +113,10 @@ angular.module('portainer.app').factory('StateManager', [ state.application.enableVolumeBrowserForNonAdminUsers = settings.AllowVolumeBrowserForRegularUsers; state.application.enableEdgeComputeFeatures = settings.EnableEdgeComputeFeatures; state.application.allowStackManagementForRegularUsers = settings.AllowStackManagementForRegularUsers; + state.application.allowBindMountsForRegularUsers = settings.AllowBindMountsForRegularUsers; + state.application.allowPrivilegedModeForRegularUsers = settings.AllowPrivilegedModeForRegularUsers; state.application.allowDeviceMappingForRegularUsers = settings.AllowDeviceMappingForRegularUsers; + state.application.allowHostNamespaceForRegularUsers = settings.AllowHostNamespaceForRegularUsers; state.application.validity = moment().unix(); } diff --git a/app/portainer/views/settings/settings.html b/app/portainer/views/settings/settings.html index a45d1e316..1c43a7bb0 100644 --- a/app/portainer/views/settings/settings.html +++ b/app/portainer/views/settings/settings.html @@ -152,6 +152,12 @@ + +
+ + Note: The recreate/duplicate/edit feature is currently disabled (for non-admin users) by one or more security settings. + +
diff --git a/app/portainer/views/settings/settingsController.js b/app/portainer/views/settings/settingsController.js index 7285051e3..8e85e4938 100644 --- a/app/portainer/views/settings/settingsController.js +++ b/app/portainer/views/settings/settingsController.js @@ -38,6 +38,11 @@ angular.module('portainer.app').controller('SettingsController', [ allowDeviceMappingForRegularUsers: false, }; + $scope.isContainerEditDisabled = function isContainerEditDisabled() { + const { restrictBindMounts, restrictHostNamespaceForRegularUsers, restrictPrivilegedMode, disableDeviceMappingForRegularUsers } = this.formValues; + return restrictBindMounts || restrictHostNamespaceForRegularUsers || restrictPrivilegedMode || disableDeviceMappingForRegularUsers; + }; + $scope.removeFilteredContainerLabel = function (index) { var settings = $scope.settings; settings.BlackListedLabels.splice(index, 1); @@ -92,6 +97,8 @@ angular.module('portainer.app').controller('SettingsController', [ StateManager.updateAllowStackManagementForRegularUsers(settings.AllowStackManagementForRegularUsers); StateManager.updateAllowHostNamespaceForRegularUsers(settings.AllowHostNamespaceForRegularUsers); StateManager.updateAllowDeviceMappingForRegularUsers(settings.AllowDeviceMappingForRegularUsers); + StateManager.updateAllowPrivilegedModeForRegularUsers(settings.AllowPrivilegedModeForRegularUsers); + StateManager.updateAllowBindMountsForRegularUsers(settings.AllowBindMountsForRegularUsers); $state.reload(); }) .catch(function error(err) {