diff --git a/doc/source/configuration/settings.rst b/doc/source/configuration/settings.rst index 8bab749aac..a4047012db 100644 --- a/doc/source/configuration/settings.rst +++ b/doc/source/configuration/settings.rst @@ -772,12 +772,18 @@ Default: 'OPENSTACK_HYPERVISOR_FEATURES', 'LAUNCH_INSTANCE_DEFAULTS', 'OPENSTACK_IMAGE_FORMATS', - 'OPENSTACK_KEYSTONE_DEFAULT_DOMAIN' + 'OPENSTACK_KEYSTONE_BACKEND', + 'OPENSTACK_KEYSTONE_DEFAULT_DOMAIN', + 'CREATE_IMAGE_DEFAULTS', + 'ENFORCE_PASSWORD_CHECK' ] This setting allows you to expose configuration values over Horizons internal REST API, so that the AngularJS panels can access them. Please be cautious -about which values are listed here (and thus exposed on the frontend) +about which values are listed here (and thus exposed on the frontend). +For security purpose, this exposure of settings should be recognized explicitly +by operator. So ``REST_API_REQUIRED_SETTINGS`` is not set by default. +Please refer ``local_settings.py.example`` and confirm your ``local_settings.py``. SELECTABLE_THEMES --------------------- diff --git a/openstack_dashboard/dashboards/identity/static/dashboard/identity/roles/actions/create.action.service.js b/openstack_dashboard/dashboards/identity/static/dashboard/identity/roles/actions/create.action.service.js index c718952543..f41eb26887 100644 --- a/openstack_dashboard/dashboards/identity/static/dashboard/identity/roles/actions/create.action.service.js +++ b/openstack_dashboard/dashboards/identity/static/dashboard/identity/roles/actions/create.action.service.js @@ -22,6 +22,7 @@ .factory('horizon.dashboard.identity.roles.actions.create.service', createService); createService.$inject = [ + '$q', 'horizon.dashboard.identity.roles.resourceType', 'horizon.dashboard.identity.roles.role-schema', 'horizon.app.core.openstack-service-api.keystone', @@ -38,6 +39,7 @@ * @Description A service to handle the Create Role modal. */ function createService( + $q, resourceType, schema, keystoneAPI, @@ -58,7 +60,10 @@ ////////////// function allowed() { - return policy.ifAllowed({ rules: [['identity', 'identity:create_role']] }); + return $q.all([ + keystoneAPI.canEditIdentity('role'), + policy.ifAllowed({ rules: [['identity', 'identity:create_role']] }) + ]); } function perform() { diff --git a/openstack_dashboard/dashboards/identity/static/dashboard/identity/roles/actions/create.action.service.spec.js b/openstack_dashboard/dashboards/identity/static/dashboard/identity/roles/actions/create.action.service.spec.js index 13622b4806..63aea44ff3 100644 --- a/openstack_dashboard/dashboards/identity/static/dashboard/identity/roles/actions/create.action.service.spec.js +++ b/openstack_dashboard/dashboards/identity/static/dashboard/identity/roles/actions/create.action.service.spec.js @@ -38,23 +38,43 @@ resType = $injector.get('horizon.dashboard.identity.roles.resourceType'); })); - it('should check the policy if the user is allowed to create roles', function() { - var deferred = $q.defer(); - spyOn(policyAPI, 'ifAllowed').and.returnValue(deferred.promise); - deferred.resolve({allowed: true}); - var handler = jasmine.createSpyObj('handler', ['success']); + it('should allow if can_edit_role is set True in OPENSTACK_KEYSTONE_BACKEND', function() { + //for canEditRole + var deferredCanEditRole = $q.defer(); + deferredCanEditRole.resolve(true); + spyOn(keystoneAPI, 'canEditIdentity').and.returnValue(deferredCanEditRole.promise); - service.allowed().then(handler.success); + //for ifAllowed + var deferredIfAllowed = $q.defer(); + deferredIfAllowed.resolve(true); + spyOn(policyAPI, 'ifAllowed').and.returnValue(deferredIfAllowed.promise); + + var allowed = service.allowed({id: '1234'}); $scope.$apply(); - expect(handler.success).toHaveBeenCalled(); - var allowed = handler.success.calls.first().args[0]; - expect(allowed).toBeTruthy(); expect(policyAPI.ifAllowed).toHaveBeenCalledWith( { rules: [['identity', 'identity:create_role']] }); }); + it('should allow if can_edit_role is set True in OPENSTACK_KEYSTONE_BACKEND', function() { + //for canEditRole + var deferredCanEditRole = $q.defer(); + deferredCanEditRole.resolve(false); + spyOn(keystoneAPI, 'canEditIdentity').and.returnValue(deferredCanEditRole.promise); + + //for ifAllowed + var deferredIfAllowed = $q.defer(); + deferredIfAllowed.resolve(true); + spyOn(policyAPI, 'ifAllowed').and.returnValue(deferredIfAllowed.promise); + + var allowed = service.allowed({id: '1234'}); + $scope.$apply(); + + // reject + expect(allowed.$$state.status).toEqual(1); + }); + it('should open the modal with the correct parameters', function() { var deferred = $q.defer(); spyOn(modalFormService, 'open').and.returnValue(deferred.promise); diff --git a/openstack_dashboard/dashboards/identity/static/dashboard/identity/roles/actions/delete.action.service.js b/openstack_dashboard/dashboards/identity/static/dashboard/identity/roles/actions/delete.action.service.js index 6f88b5ccc3..6f84dbe8a5 100644 --- a/openstack_dashboard/dashboards/identity/static/dashboard/identity/roles/actions/delete.action.service.js +++ b/openstack_dashboard/dashboards/identity/static/dashboard/identity/roles/actions/delete.action.service.js @@ -22,6 +22,7 @@ .factory('horizon.dashboard.identity.roles.actions.delete.service', deleteRoleService); deleteRoleService.$inject = [ + '$q', 'horizon.app.core.openstack-service-api.keystone', 'horizon.app.core.openstack-service-api.policy', 'horizon.framework.util.actions.action-result.service', @@ -41,6 +42,7 @@ * On cancel, do nothing. */ function deleteRoleService( + $q, keystone, policy, actionResultService, @@ -57,7 +59,10 @@ ////////////// function allowed() { - return policy.ifAllowed({rules: [[ 'identity', 'identity:delete_role' ]]}); + return $q.all([ + keystone.canEditIdentity('role'), + policy.ifAllowed({ rules: [['identity', 'identity:delete_role']] }) + ]); } function perform(items, scope) { diff --git a/openstack_dashboard/dashboards/identity/static/dashboard/identity/roles/actions/delete.action.service.spec.js b/openstack_dashboard/dashboards/identity/static/dashboard/identity/roles/actions/delete.action.service.spec.js index e6aef1f1a9..0b7f879e42 100644 --- a/openstack_dashboard/dashboards/identity/static/dashboard/identity/roles/actions/delete.action.service.spec.js +++ b/openstack_dashboard/dashboards/identity/static/dashboard/identity/roles/actions/delete.action.service.spec.js @@ -20,9 +20,10 @@ beforeEach(module('horizon.dashboard.identity.roles')); beforeEach(module('horizon.framework')); - var deleteModalService, service, keystoneAPI, policyAPI; + var deleteModalService, $scope, service, keystoneAPI, policyAPI; - beforeEach(inject(function($injector) { + beforeEach(inject(function($injector, _$rootScope_) { + $scope = _$rootScope_.$new(); service = $injector.get('horizon.dashboard.identity.roles.actions.delete.service'); keystoneAPI = $injector.get('horizon.app.core.openstack-service-api.keystone'); deleteModalService = $injector.get('horizon.framework.widgets.modal.deleteModalService'); @@ -72,8 +73,11 @@ describe('allow method', function() { it('should use default policy if batch action', function test() { + spyOn(keystoneAPI, 'canEditIdentity'); spyOn(policyAPI, 'ifAllowed'); service.allowed(); + $scope.$apply(); + expect(keystoneAPI.canEditIdentity).toHaveBeenCalled(); expect(policyAPI.ifAllowed).toHaveBeenCalled(); }); }); // end of allowed diff --git a/openstack_dashboard/dashboards/identity/static/dashboard/identity/roles/actions/edit.action.service.js b/openstack_dashboard/dashboards/identity/static/dashboard/identity/roles/actions/edit.action.service.js index dce2bb9134..4641f17b59 100644 --- a/openstack_dashboard/dashboards/identity/static/dashboard/identity/roles/actions/edit.action.service.js +++ b/openstack_dashboard/dashboards/identity/static/dashboard/identity/roles/actions/edit.action.service.js @@ -22,6 +22,7 @@ .factory('horizon.dashboard.identity.roles.actions.edit.service', editService); editService.$inject = [ + '$q', 'horizon.dashboard.identity.roles.resourceType', 'horizon.dashboard.identity.roles.role-schema', 'horizon.app.core.openstack-service-api.keystone', @@ -37,6 +38,7 @@ * @Description A service to handle the Edit Role modal. */ function editService( + $q, resourceType, schema, keystoneAPI, @@ -58,7 +60,10 @@ ////////////// function allowed() { - return policy.ifAllowed({ rules: [['identity', 'identity:update_role']] }); + return $q.all([ + keystoneAPI.canEditIdentity('role'), + policy.ifAllowed({ rules: [['identity', 'identity:update_role']] }) + ]); } function perform(role) { diff --git a/openstack_dashboard/dashboards/identity/static/dashboard/identity/roles/actions/edit.action.service.spec.js b/openstack_dashboard/dashboards/identity/static/dashboard/identity/roles/actions/edit.action.service.spec.js index 5d0e6b5988..b17cee12ed 100644 --- a/openstack_dashboard/dashboards/identity/static/dashboard/identity/roles/actions/edit.action.service.spec.js +++ b/openstack_dashboard/dashboards/identity/static/dashboard/identity/roles/actions/edit.action.service.spec.js @@ -92,8 +92,10 @@ describe('allow method', function() { it('should use default policy if batch action', function test() { + spyOn(keystoneAPI, 'canEditIdentity'); spyOn(policyAPI, 'ifAllowed'); service.allowed(); + expect(keystoneAPI.canEditIdentity).toHaveBeenCalled(); expect(policyAPI.ifAllowed).toHaveBeenCalled(); }); }); // end of allowed diff --git a/openstack_dashboard/dashboards/identity/static/dashboard/identity/users/actions/create.action.service.js b/openstack_dashboard/dashboards/identity/static/dashboard/identity/users/actions/create.action.service.js index 8f1c7f96d1..a6c1077504 100644 --- a/openstack_dashboard/dashboards/identity/static/dashboard/identity/users/actions/create.action.service.js +++ b/openstack_dashboard/dashboards/identity/static/dashboard/identity/users/actions/create.action.service.js @@ -62,7 +62,10 @@ ////////////// function allowed() { - return policy.ifAllowed({ rules: [['identity', 'identity:create_user']] }); + return $q.all([ + keystone.canEditIdentity('user'), + policy.ifAllowed({ rules: [['identity', 'identity:create_user']] }) + ]); } function perform() { diff --git a/openstack_dashboard/dashboards/identity/static/dashboard/identity/users/actions/create.action.service.spec.js b/openstack_dashboard/dashboards/identity/static/dashboard/identity/users/actions/create.action.service.spec.js index d7d0450bee..78392ef9c9 100644 --- a/openstack_dashboard/dashboards/identity/static/dashboard/identity/users/actions/create.action.service.spec.js +++ b/openstack_dashboard/dashboards/identity/static/dashboard/identity/users/actions/create.action.service.spec.js @@ -38,23 +38,43 @@ resourceType = $injector.get('horizon.dashboard.identity.users.resourceType'); })); - it('should check the policy if the user is allowed to create user', function() { - var deferred = $q.defer(); - spyOn(policy, 'ifAllowed').and.returnValue(deferred.promise); - deferred.resolve({allowed: true}); - var handler = jasmine.createSpyObj('handler', ['success']); + it('should allow if can_edit_user is set True in OPENSTACK_KEYSTONE_BACKEND', function() { + //for canEditUser + var deferredCanEditUser = $q.defer(); + deferredCanEditUser.resolve(true); + spyOn(keystone, 'canEditIdentity').and.returnValue(deferredCanEditUser.promise); - service.allowed().then(handler.success); + //for ifAllowed + var deferredIfAllowed = $q.defer(); + deferredIfAllowed.resolve(true); + spyOn(policy, 'ifAllowed').and.returnValue(deferredIfAllowed.promise); + + var allowed = service.allowed({id: '1234'}); $scope.$apply(); - expect(handler.success).toHaveBeenCalled(); - var allowed = handler.success.calls.first().args[0]; - expect(allowed).toBeTruthy(); expect(policy.ifAllowed).toHaveBeenCalledWith( { rules: [['identity', 'identity:create_user']] }); }); + it('should allow if can_edit_user is set True in OPENSTACK_KEYSTONE_BACKEND', function() { + //for canEditUser + var deferredCanEditUser = $q.defer(); + deferredCanEditUser.resolve(false); + spyOn(keystone, 'canEditIdentity').and.returnValue(deferredCanEditUser.promise); + + //for ifAllowed + var deferredIfAllowed = $q.defer(); + deferredIfAllowed.resolve(true); + spyOn(policy, 'ifAllowed').and.returnValue(deferredIfAllowed.promise); + + var allowed = service.allowed({id: '1234'}); + $scope.$apply(); + + // reject + expect(allowed.$$state.status).toEqual(1); + }); + it('should open the modal', function() { spyOn(modal, 'open').and.returnValue($q.defer().promise); spyOn(keystone, 'getVersion').and.returnValue($q.defer().promise); diff --git a/openstack_dashboard/dashboards/identity/static/dashboard/identity/users/actions/delete.action.service.js b/openstack_dashboard/dashboards/identity/static/dashboard/identity/users/actions/delete.action.service.js index e4d12f259f..bd579fb962 100644 --- a/openstack_dashboard/dashboards/identity/static/dashboard/identity/users/actions/delete.action.service.js +++ b/openstack_dashboard/dashboards/identity/static/dashboard/identity/users/actions/delete.action.service.js @@ -63,7 +63,10 @@ ////////////// function allowed() { - return policy.ifAllowed({rules: [[ 'identity', 'identity:delete_user' ]]}); + return $q.all([ + keystone.canEditIdentity('user'), + policy.ifAllowed({ rules: [['identity', 'identity:delete_user']] }) + ]); } function perform(items, scope) { diff --git a/openstack_dashboard/dashboards/identity/static/dashboard/identity/users/actions/delete.action.service.spec.js b/openstack_dashboard/dashboards/identity/static/dashboard/identity/users/actions/delete.action.service.spec.js index d813654763..bd15cee195 100644 --- a/openstack_dashboard/dashboards/identity/static/dashboard/identity/users/actions/delete.action.service.spec.js +++ b/openstack_dashboard/dashboards/identity/static/dashboard/identity/users/actions/delete.action.service.spec.js @@ -37,6 +37,9 @@ var keystoneAPI = { deleteUser: function() { return; + }, + canEditIdentity: function() { + return; } }; @@ -75,6 +78,7 @@ beforeEach(module('horizon.app.core.openstack-service-api', function($provide) { $provide.value('horizon.app.core.openstack-service-api.keystone', keystoneAPI); $provide.value('horizon.app.core.openstack-service-api.policy', policyAPI); + spyOn(keystoneAPI, 'canEditIdentity').and.callThrough(); spyOn(policyAPI, 'ifAllowed').and.callThrough(); })); @@ -134,7 +138,7 @@ it('should call policy check', function() { service.allowed(); $scope.$apply(); - + expect(keystoneAPI.canEditIdentity).toHaveBeenCalled(); expect(policyAPI.ifAllowed).toHaveBeenCalled(); }); }); diff --git a/openstack_dashboard/dashboards/identity/static/dashboard/identity/users/actions/disable.action.service.js b/openstack_dashboard/dashboards/identity/static/dashboard/identity/users/actions/disable.action.service.js index 16ee552936..566ca85694 100644 --- a/openstack_dashboard/dashboards/identity/static/dashboard/identity/users/actions/disable.action.service.js +++ b/openstack_dashboard/dashboards/identity/static/dashboard/identity/users/actions/disable.action.service.js @@ -58,6 +58,7 @@ function allowed(selected) { return $q.all([ + keystone.canEditIdentity('user'), $qExtensions.booleanAsPromise(selected.enabled), policy.ifAllowed({ rules: [['identity', 'identity:update_user']] }) ]); diff --git a/openstack_dashboard/dashboards/identity/static/dashboard/identity/users/actions/disable.action.service.spec.js b/openstack_dashboard/dashboards/identity/static/dashboard/identity/users/actions/disable.action.service.spec.js index 131b0583e8..d20be522fb 100644 --- a/openstack_dashboard/dashboards/identity/static/dashboard/identity/users/actions/disable.action.service.spec.js +++ b/openstack_dashboard/dashboards/identity/static/dashboard/identity/users/actions/disable.action.service.spec.js @@ -35,6 +35,9 @@ var deferred = $q.defer(); spyOn(keystone, 'editUser').and.returnValue(deferred.promise); deferred.resolve({}); + var deferredCanEdit = $q.defer(); + spyOn(keystone, 'canEditIdentity').and.returnValue(deferredCanEdit.promise); + deferredCanEdit.resolve(true); policy = $injector.get('horizon.app.core.openstack-service-api.policy'); var allowedPromise = $q.defer(); spyOn(policy, 'ifAllowed').and.returnValue(allowedPromise.promise); diff --git a/openstack_dashboard/dashboards/identity/static/dashboard/identity/users/actions/enable.action.service.js b/openstack_dashboard/dashboards/identity/static/dashboard/identity/users/actions/enable.action.service.js index 61a299bce9..79fe2b9b8a 100644 --- a/openstack_dashboard/dashboards/identity/static/dashboard/identity/users/actions/enable.action.service.js +++ b/openstack_dashboard/dashboards/identity/static/dashboard/identity/users/actions/enable.action.service.js @@ -58,6 +58,7 @@ function allowed(selected) { return $q.all([ + keystone.canEditIdentity('user'), $qExtensions.booleanAsPromise(!selected.enabled), policy.ifAllowed({ rules: [['identity', 'identity:update_user']] }) ]); diff --git a/openstack_dashboard/dashboards/identity/static/dashboard/identity/users/actions/enable.action.service.spec.js b/openstack_dashboard/dashboards/identity/static/dashboard/identity/users/actions/enable.action.service.spec.js index e51a9cf386..74dab8390d 100644 --- a/openstack_dashboard/dashboards/identity/static/dashboard/identity/users/actions/enable.action.service.spec.js +++ b/openstack_dashboard/dashboards/identity/static/dashboard/identity/users/actions/enable.action.service.spec.js @@ -35,6 +35,9 @@ var deferred = $q.defer(); spyOn(keystone, 'editUser').and.returnValue(deferred.promise); deferred.resolve({}); + var deferredCanEdit = $q.defer(); + spyOn(keystone, 'canEditIdentity').and.returnValue(deferredCanEdit.promise); + deferredCanEdit.resolve(true); policy = $injector.get('horizon.app.core.openstack-service-api.policy'); var allowedPromise = $q.defer(); spyOn(policy, 'ifAllowed').and.returnValue(allowedPromise.promise); diff --git a/openstack_dashboard/dashboards/identity/static/dashboard/identity/users/actions/password.action.service.js b/openstack_dashboard/dashboards/identity/static/dashboard/identity/users/actions/password.action.service.js index af939a3e77..8d33b0e69e 100644 --- a/openstack_dashboard/dashboards/identity/static/dashboard/identity/users/actions/password.action.service.js +++ b/openstack_dashboard/dashboards/identity/static/dashboard/identity/users/actions/password.action.service.js @@ -62,7 +62,10 @@ ////////////// function allowed() { - return policy.ifAllowed({ rules: [['identity', 'identity:update_user']] }); + return $q.all([ + keystone.canEditIdentity('user'), + policy.ifAllowed({ rules: [['identity', 'identity:update_user']] }) + ]); } // eslint-disable-next-line no-unused-vars diff --git a/openstack_dashboard/dashboards/identity/static/dashboard/identity/users/actions/password.action.service.spec.js b/openstack_dashboard/dashboards/identity/static/dashboard/identity/users/actions/password.action.service.spec.js index ee6e7688c2..196d573239 100644 --- a/openstack_dashboard/dashboards/identity/static/dashboard/identity/users/actions/password.action.service.spec.js +++ b/openstack_dashboard/dashboards/identity/static/dashboard/identity/users/actions/password.action.service.spec.js @@ -40,6 +40,9 @@ var deferred = $q.defer(); spyOn(policy, 'ifAllowed').and.returnValue(deferred.promise); deferred.resolve({allowed: true}); + var deferredCanEdit = $q.defer(); + spyOn(keystone, 'canEditIdentity').and.returnValue(deferredCanEdit.promise); + deferredCanEdit.resolve(true); var handler = jasmine.createSpyObj('handler', ['success']); service.allowed().then(handler.success); diff --git a/openstack_dashboard/dashboards/identity/static/dashboard/identity/users/actions/update.action.service.js b/openstack_dashboard/dashboards/identity/static/dashboard/identity/users/actions/update.action.service.js index 3d9c00cf20..ee24992ce9 100644 --- a/openstack_dashboard/dashboards/identity/static/dashboard/identity/users/actions/update.action.service.js +++ b/openstack_dashboard/dashboards/identity/static/dashboard/identity/users/actions/update.action.service.js @@ -60,7 +60,10 @@ ////////////// function allowed() { - return policy.ifAllowed({ rules: [['identity', 'identity:update_user']] }); + return $q.all([ + keystone.canEditIdentity('user'), + policy.ifAllowed({ rules: [['identity', 'identity:update_user']] }) + ]); } function perform(selected) { diff --git a/openstack_dashboard/dashboards/identity/static/dashboard/identity/users/actions/update.action.service.spec.js b/openstack_dashboard/dashboards/identity/static/dashboard/identity/users/actions/update.action.service.spec.js index 1972aded9d..0e13c8ce90 100644 --- a/openstack_dashboard/dashboards/identity/static/dashboard/identity/users/actions/update.action.service.spec.js +++ b/openstack_dashboard/dashboards/identity/static/dashboard/identity/users/actions/update.action.service.spec.js @@ -39,6 +39,9 @@ var deferred = $q.defer(); spyOn(policy, 'ifAllowed').and.returnValue(deferred.promise); deferred.resolve({allowed: true}); + var deferredCanEdit = $q.defer(); + spyOn(keystone, 'canEditIdentity').and.returnValue(deferredCanEdit.promise); + deferredCanEdit.resolve(true); var handler = jasmine.createSpyObj('handler', ['success']); service.allowed().then(handler.success); diff --git a/openstack_dashboard/local/local_settings.py.example b/openstack_dashboard/local/local_settings.py.example index d21242f61f..d2fd38a88f 100644 --- a/openstack_dashboard/local/local_settings.py.example +++ b/openstack_dashboard/local/local_settings.py.example @@ -790,6 +790,7 @@ SECURITY_GROUP_RULES = { REST_API_REQUIRED_SETTINGS = ['OPENSTACK_HYPERVISOR_FEATURES', 'LAUNCH_INSTANCE_DEFAULTS', 'OPENSTACK_IMAGE_FORMATS', + 'OPENSTACK_KEYSTONE_BACKEND', 'OPENSTACK_KEYSTONE_DEFAULT_DOMAIN', 'CREATE_IMAGE_DEFAULTS', 'ENFORCE_PASSWORD_CHECK'] diff --git a/openstack_dashboard/static/app/core/openstack-service-api/keystone.service.js b/openstack_dashboard/static/app/core/openstack-service-api/keystone.service.js index 4c1946f5e1..6c28e27ca9 100644 --- a/openstack_dashboard/static/app/core/openstack-service-api/keystone.service.js +++ b/openstack_dashboard/static/app/core/openstack-service-api/keystone.service.js @@ -22,11 +22,12 @@ keystoneAPI.$inject = [ '$q', + 'horizon.app.core.openstack-service-api.settings', 'horizon.framework.util.http.service', 'horizon.framework.widgets.toast.service' ]; - function keystoneAPI($q, apiService, toastService) { + function keystoneAPI($q, settingAPI, apiService, toastService) { var service = { getVersion: getVersion, getUsers: getUsers, @@ -64,7 +65,8 @@ getGroup: getGroup, editGroup: editGroup, deleteGroup: deleteGroup, - deleteGroups: deleteGroups + deleteGroups: deleteGroups, + canEditIdentity: canEditIdentity }; return service; @@ -385,6 +387,26 @@ }); } + /** + * @name canEditIdentity + * @description + * Returns the promise for can_edit_* setting in OPENSTACK_KEYSTONE_BACKEND. + * @returns {object} Deferred promiss + */ + function canEditIdentity(type) { + var deferred = $q.defer(); + settingAPI.getSetting('OPENSTACK_KEYSTONE_BACKEND', false).then(success); + return deferred.promise; + + function success(response) { + if (response["can_edit_" + type]) { + deferred.resolve(); + } else { + deferred.reject(); + } + } + } + /** * @name serviceCatalog * @description diff --git a/openstack_dashboard/static/app/core/openstack-service-api/keystone.service.spec.js b/openstack_dashboard/static/app/core/openstack-service-api/keystone.service.spec.js index 3ee0814700..04894f804f 100644 --- a/openstack_dashboard/static/app/core/openstack-service-api/keystone.service.spec.js +++ b/openstack_dashboard/static/app/core/openstack-service-api/keystone.service.spec.js @@ -18,7 +18,7 @@ 'use strict'; describe('Keystone API', function() { - var testCall, service; + var testCall, service, settings; var apiService = {}; var toastService = {}; @@ -31,9 +31,10 @@ beforeEach(module('horizon.app.core.openstack-service-api')); - beforeEach(inject(['horizon.app.core.openstack-service-api.keystone', function(keystoneAPI) { - service = keystoneAPI; - }])); + beforeEach(inject(function($injector) { + service = $injector.get('horizon.app.core.openstack-service-api.keystone'); + settings = $injector.get('horizon.app.core.openstack-service-api.settings'); + })); it('defines the service', function() { expect(service).toBeDefined(); @@ -508,6 +509,32 @@ }); }); + + describe('canEditIdentity', function () { + var deferred, $timeout; + + beforeEach(inject(function (_$q_, _$timeout_) { + deferred = _$q_.defer(); + $timeout = _$timeout_; + })); + + it('should resolve true if can_edit_group is set True', function() { + deferred.resolve({can_edit_group: true}); + spyOn(settings, 'getSettings').and.returnValue(deferred.promise); + var canEdit = service.canEditIdentity('group'); + $timeout.flush(); + expect(canEdit).toBeTruthy(); + }); + + it('should resolve false if can_edit_group is set False', function() { + deferred.resolve({can_edit_group: false}); + spyOn(settings, 'getSettings').and.returnValue(deferred.promise); + var canEdit = service.canEditIdentity('group'); + $timeout.flush(); + // reject + expect(canEdit.$$state.status).toEqual(2); + }); + }); }); })(); diff --git a/releasenotes/notes/bug-1779268-44848e4d2c69fddc.yaml b/releasenotes/notes/bug-1779268-44848e4d2c69fddc.yaml new file mode 100644 index 0000000000..c11a1a2e3d --- /dev/null +++ b/releasenotes/notes/bug-1779268-44848e4d2c69fddc.yaml @@ -0,0 +1,15 @@ +--- +fixes: + - | + [:bug:`1779268`] Supported ``can_edit_*`` settings in Angularized identity + panels. To enable this settings in Angularized identity panels, add + ``OPENSTACK_KEYSTONE_BACKEND`` into ``REST_API_REQUIRED_SETTINGS`` on + ``local_settings.py``. For more detail, see + `REST_API_REQUIRED_SETTINGS `__ + in horizon settings documentation. +upgrade: + - | + Add ``OPENSTACK_KEYSTONE_BACKEND`` manually into + ``REST_API_REQUIRED_SETTINGS`` on ``local_settings.py``, if your deployment + uses Angularized identity panels and needs to enable ``can_edit_*`` + settings in ``OPENSTACK_KEYSTONE_BACKEND``.