Support can_edit_user and can_edit_role settings in Angularized panels
The actions on Angularized users panel and roles panel does not support following setting. OPENSTACK_KEYSTONE_BACKEND = { 'can_edit_user': True, 'can_edit_role': True, } This patch enables to support these settings. To enable this settings, add 'OPENSTACK_KEYSTONE_BACKEND' into 'REST_API_REQUIRED_SETTINGS' setting. Change-Id: I7888bd2c2977dc010911d2e7ecf42815354e081b Closes-Bug: #1779268
This commit is contained in:
parent
ab03c13711
commit
e20882d3b3
@ -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
|
||||
---------------------
|
||||
|
@ -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() {
|
||||
|
@ -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);
|
||||
|
@ -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) {
|
||||
|
@ -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
|
||||
|
@ -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) {
|
||||
|
@ -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
|
||||
|
@ -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() {
|
||||
|
@ -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);
|
||||
|
@ -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) {
|
||||
|
@ -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();
|
||||
});
|
||||
});
|
||||
|
@ -58,6 +58,7 @@
|
||||
|
||||
function allowed(selected) {
|
||||
return $q.all([
|
||||
keystone.canEditIdentity('user'),
|
||||
$qExtensions.booleanAsPromise(selected.enabled),
|
||||
policy.ifAllowed({ rules: [['identity', 'identity:update_user']] })
|
||||
]);
|
||||
|
@ -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);
|
||||
|
@ -58,6 +58,7 @@
|
||||
|
||||
function allowed(selected) {
|
||||
return $q.all([
|
||||
keystone.canEditIdentity('user'),
|
||||
$qExtensions.booleanAsPromise(!selected.enabled),
|
||||
policy.ifAllowed({ rules: [['identity', 'identity:update_user']] })
|
||||
]);
|
||||
|
@ -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);
|
||||
|
@ -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
|
||||
|
@ -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);
|
||||
|
@ -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) {
|
||||
|
@ -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);
|
||||
|
@ -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']
|
||||
|
@ -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
|
||||
|
@ -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);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
})();
|
||||
|
15
releasenotes/notes/bug-1779268-44848e4d2c69fddc.yaml
Normal file
15
releasenotes/notes/bug-1779268-44848e4d2c69fddc.yaml
Normal file
@ -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 <https://docs.openstack.org/horizon/latest/configuration/settings.html#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``.
|
Loading…
Reference in New Issue
Block a user