Add policy checks in images panels

check policy of getting images in:
project/images
project/ngimages
admin/images

Only block listing images but not whole panel if failed on policy check.
Create, Delete and other actions are controlled by according policys.
give a message "Insufficient privilege level to get images." to user
if polciy checks failed.

Closes-Bug: #1529012
Change-Id: I97ab081425dd56fa7c3208efb58ba8b041eaba24
This commit is contained in:
Bo Wang 2016-04-12 14:16:11 +08:00 committed by wangbo
parent ea8e7a504a
commit 340e67c17a
4 changed files with 63 additions and 3 deletions

View File

@ -25,10 +25,12 @@ from django.core.urlresolvers import reverse_lazy
from django.utils.translation import ugettext_lazy as _
from horizon import exceptions
from horizon import messages
from horizon import tables
from openstack_dashboard import api
from openstack_dashboard.dashboards.project.images.images import views
from openstack_dashboard import policy
from openstack_dashboard.dashboards.admin.images import forms as project_forms
from openstack_dashboard.dashboards.admin.images \
@ -51,6 +53,10 @@ class IndexView(tables.DataTableView):
def get_data(self):
images = []
if not policy.check((("image", "get_images"),), self.request):
msg = _("Insufficient privilege level to retrieve image list.")
messages.info(self.request, msg)
return images
filters = self.get_filters()
prev_marker = self.request.GET.get(
project_tables.AdminImagesTable._meta.prev_pagination_param, None)

View File

@ -24,9 +24,11 @@ Views for managing Images and Snapshots.
from django.utils.translation import ugettext_lazy as _
from horizon import exceptions
from horizon import messages
from horizon import tables
from openstack_dashboard import api
from openstack_dashboard import policy
from openstack_dashboard.dashboards.project.images.images \
import tables as images_tables
@ -44,6 +46,10 @@ class IndexView(tables.DataTableView):
return getattr(self, "_more", False)
def get_data(self):
if not policy.check((("image", "get_images"),), self.request):
msg = _("Insufficient privilege level to retrieve image list.")
messages.info(self.request, msg)
return []
prev_marker = self.request.GET.get(
images_tables.ImagesTable._meta.prev_pagination_param, None)

View File

@ -24,10 +24,12 @@
ImagesTableController.$inject = [
'$q',
'$scope',
'horizon.framework.widgets.toast.service',
'horizon.app.core.images.detailsRoute',
'horizon.app.core.images.events',
'horizon.app.core.images.resourceType',
'horizon.app.core.openstack-service-api.glance',
'horizon.app.core.openstack-service-api.policy',
'horizon.app.core.openstack-service-api.userSession',
'horizon.framework.conf.resource-type-registry.service',
'horizon.framework.util.actions.action-result.service',
@ -56,10 +58,12 @@
function ImagesTableController(
$q,
$scope,
toast,
detailsRoute,
events,
imageResourceType,
glance,
policy,
userSession,
typeRegistry,
actionResultService,
@ -77,10 +81,19 @@
ctrl.actionResultHandler = actionResultHandler;
typeRegistry.initActions(imageResourceType, $scope);
loadImages();
init();
////////////////////////////////
function init() {
// if user has permission
// fetch table data and populate it
ctrl.images = [];
ctrl.imagesSrc = [];
var rules = [['image', 'get_images']];
policy.ifAllowed({ rules: rules }).then(loadImages, policyFailed);
}
function loadImages() {
ctrl.images = [];
ctrl.imagesSrc = [];
@ -105,6 +118,11 @@
applyMetadataDefinitions();
}
function policyFailed() {
var msg = gettext('Insufficient privilege level to get images.');
toast.add('info', msg);
}
function difference(currentList, otherList, key) {
return currentList.filter(filter);

View File

@ -44,6 +44,17 @@
}
};
var policy = { allowed: true };
function fakePolicy() {
return {
then: function(successFn, errorFn) {
if (policy.allowed) { successFn(); }
else { errorFn(); }
}
};
}
function fakeToast() { return { add: angular.noop }; }
var userSession = {
get: function () {
return {project_id: '123'};
@ -68,7 +79,7 @@
2: {id: '2', is_public: false, owner: 'not_me', filtered_visibility: 'Shared with Me'}
};
var $scope, controller, detailsRoute;
var $scope, controller, toastService, detailsRoute, policyAPI;
beforeEach(module('ui.bootstrap'));
beforeEach(module('horizon.framework'));
@ -88,9 +99,14 @@
beforeEach(inject(function ($injector, _$rootScope_) {
$scope = _$rootScope_.$new();
toastService = $injector.get('horizon.framework.widgets.toast.service');
policyAPI = $injector.get('horizon.app.core.openstack-service-api.policy');
controller = $injector.get('$controller');
detailsRoute = $injector.get('horizon.app.core.images.detailsRoute');
spyOn(toastService, 'add').and.callFake(fakeToast);
spyOn(policyAPI, 'ifAllowed').and.callFake(fakePolicy);
spyOn(glanceAPI, 'getImages').and.callThrough();
spyOn(glanceAPI, 'getNamespaces').and.callThrough();
spyOn(userSession, 'get').and.callThrough();
@ -100,6 +116,8 @@
function createController() {
return controller('horizon.app.core.images.table.ImagesController', {
toast: toastService,
policyAPI: policyAPI,
glanceAPI: glanceAPI,
userSession: userSession,
$q: mockQ,
@ -113,9 +131,12 @@
});
it('should invoke initialization apis', function() {
policy.allowed = true;
var ctrl = createController();
expect(userSession.get).toHaveBeenCalled();
expect(policyAPI.ifAllowed).toHaveBeenCalled();
expect(glanceAPI.getImages).toHaveBeenCalled();
expect(userSession.get).toHaveBeenCalled();
expect(ctrl.imagesSrc).toEqual([
expectedImages['1'],
expectedImages['2']
@ -186,5 +207,14 @@
]);
});
it('should not invoke glance apis if policy fails', function() {
policy.allowed = false;
createController();
expect(policyAPI.ifAllowed).toHaveBeenCalled();
expect(toastService.add).toHaveBeenCalled();
expect(glanceAPI.getImages).not.toHaveBeenCalled();
});
});
})();