Fix unauthorized exception when using member user to access angular users panel

When a member role user go to angular users panel, it will be
raised unauthorized exception since the user has no access to
get users list. It should be add a policy check mechanism at
the panel.

Change-Id: I9cfa1aeab27aca1631322d8c0b3e6a7a930d9cfe
Closes-Bug: #1694127
This commit is contained in:
wei.ying 2017-05-28 22:00:38 +08:00
parent 946ecea7b7
commit dc9a6a33ea
4 changed files with 39 additions and 13 deletions

View File

@ -123,7 +123,7 @@ class User(generic.View):
"""
if id == 'current':
id = request.user.id
return api.keystone.user_get(request, id).to_dict()
return api.keystone.user_get(request, id, admin=False).to_dict()
@rest_utils.ajax()
def delete(self, request, id):
@ -487,7 +487,7 @@ class Project(generic.View):
@rest_utils.ajax()
def get(self, request, id):
"""Get a specific project by id."""
return api.keystone.tenant_get(request, id).to_dict()
return api.keystone.tenant_get(request, id, admin=False).to_dict()
@rest_utils.ajax()
def delete(self, request, id):

View File

@ -23,6 +23,7 @@
'$q',
'horizon.app.core.openstack-service-api.keystone',
'horizon.app.core.detailRoute',
'horizon.app.core.openstack-service-api.policy',
'horizon.app.core.openstack-service-api.settings'
];
@ -30,7 +31,7 @@
* @ngdoc factory
* @name horizon.dashboard.identity.users.service
*/
function userService($q, keystone, detailRoute, settings) {
function userService($q, keystone, detailRoute, policy, settings) {
return {
getDetailsPath: getDetailsPath,
getUserPromise: getUserPromise,
@ -57,9 +58,25 @@
* Returns a promise for the users data.
*/
function getUsersPromise(params) {
return keystone.getUsers(params).then(modifyResponse);
var rules = [['identity', 'identity:list_users']];
// Check whether the user has the privilege of list_users, if so, retrieve
// all the users, otherwise only retrieve the current login user details.
return policy.ifAllowed({ rules: rules }).then(policySuccess, policyFailed);
function policySuccess() {
return keystone.getUsers(params).then(modifyResponse);
}
function policyFailed() {
// In case that a user doesn't have a privilege of list_users.
return keystone.getUser('current').then(modifyResponse);
}
function modifyResponse(response) {
if (!angular.isArray(response.data.items)) {
// the result of getUser is not array.
response.data.items = [angular.copy(response.data)];
}
return {data: {items: response.data.items.map(modifyItem)}};
function modifyItem(item) {

View File

@ -17,12 +17,13 @@
"use strict";
describe('Identity user service', function() {
var service, keystone, scope, settings, $q, detailRoute;
var service, keystone, policy, scope, settings, $q, detailRoute;
beforeEach(module('horizon.dashboard.identity.users'));
beforeEach(inject(function($injector, _$q_) {
service = $injector.get('horizon.dashboard.identity.users.service');
keystone = $injector.get('horizon.app.core.openstack-service-api.keystone');
policy = $injector.get('horizon.app.core.openstack-service-api.policy');
settings = $injector.get('horizon.app.core.openstack-service-api.settings');
detailRoute = $injector.get('horizon.app.core.detailRoute');
scope = $injector.get('$rootScope').$new();
@ -37,16 +38,21 @@
describe('getUsersPromise', function() {
it("provides a promise", function() {
var deferred = $q.defer();
spyOn(keystone, 'getUsers').and.returnValue(deferred.promise);
var deferredGetUser = $q.defer();
var deferredGetUsers = $q.defer();
var deferredPolicy = $q.defer();
spyOn(keystone, 'getUser').and.returnValue(deferredGetUser.promise);
spyOn(keystone, 'getUsers').and.returnValue(deferredGetUsers.promise);
spyOn(policy, 'ifAllowed').and.returnValue(deferredPolicy.promise);
var result = service.getUsersPromise();
deferred.resolve({data: {items: [{id: '1', name: 'puff'}]}});
deferredGetUser.resolve({data: {id: '1', name: 'puff'}});
deferredGetUsers.resolve({data: {items: [{id: '1234', name: 'test_user1'}]}});
deferredPolicy.resolve({"allowed": true});
scope.$apply();
expect(keystone.getUsers).toHaveBeenCalled();
expect(result.$$state.value.data.items[0].name).toBe('puff');
expect(result.$$state.value.data.items[0].name).toBe('test_user1');
});
});

View File

@ -48,7 +48,8 @@ class KeystoneRestTestCase(test.TestCase):
response = keystone.User().get(request, 'the_id')
self.assertStatusCode(response, 200)
self.assertEqual(response.json, {"name": "Ni!"})
self.mock_user_get.assert_called_once_with(request, 'the_id')
self.mock_user_get.assert_called_once_with(
request, 'the_id', admin=False)
@test.create_mocks({api.keystone: ['user_get']})
def test_user_get_current(self):
@ -57,7 +58,8 @@ class KeystoneRestTestCase(test.TestCase):
response = keystone.User().get(request, 'current')
self.assertStatusCode(response, 200)
self.assertEqual(response.json, {"name": "Ni!"})
self.mock_user_get.assert_called_once_with(request, 'current_id')
self.mock_user_get.assert_called_once_with(
request, 'current_id', admin=False)
@test.create_mocks({api.keystone: ['user_list']})
def test_user_get_list(self):
@ -519,7 +521,8 @@ class KeystoneRestTestCase(test.TestCase):
response = keystone.Project().get(request, 'the_id')
self.assertStatusCode(response, 200)
self.assertEqual(response.json, {"name": "Ni!"})
self.mock_tenant_get.assert_called_once_with(request, 'the_id')
self.mock_tenant_get.assert_called_once_with(
request, 'the_id', admin=False)
def test_project_get_list(self):
self._test_project_get_list(