Fix project-related forbidden response messages
When attempting to delete a project that has a child, the operation is rejected as expected, but the message said it was rejected because of an authority problem: You are not authorized to perform the requested action: cannot delete the project ... since it is not a leaf in the hierarchy. This is misleading since the problem has nothing to do with authority and granting more authority isn't going to allow the operation to work. There are several operations like this that are fixed. ForbiddenAction is meant to be used to reference the action in the policy file. Change-Id: Ibe8c1ee8e5cac7c135d0b84c5e59b630e3d91d20 Closes-Bug: 1548562
This commit is contained in:
parent
d2af8e0d6a
commit
8e2bba4829
|
@ -140,27 +140,33 @@ class CircularRegionHierarchyError(Error):
|
|||
title = 'Bad Request'
|
||||
|
||||
|
||||
class PasswordVerificationError(Error):
|
||||
class ForbiddenNotSecurity(Error):
|
||||
"""When you want to return a 403 Forbidden response but not security.
|
||||
|
||||
Use this for errors where the message is always safe to present to the user
|
||||
and won't give away extra information.
|
||||
|
||||
"""
|
||||
|
||||
code = 403
|
||||
title = 'Forbidden'
|
||||
|
||||
|
||||
class PasswordVerificationError(ForbiddenNotSecurity):
|
||||
message_format = _("The password length must be less than or equal "
|
||||
"to %(size)i. The server could not comply with the "
|
||||
"request because the password is invalid.")
|
||||
code = 403
|
||||
title = 'Forbidden'
|
||||
|
||||
|
||||
class RegionDeletionError(Error):
|
||||
class RegionDeletionError(ForbiddenNotSecurity):
|
||||
message_format = _("Unable to delete region %(region_id)s because it or "
|
||||
"its child regions have associated endpoints.")
|
||||
code = 403
|
||||
title = 'Forbidden'
|
||||
|
||||
|
||||
class PKITokenExpected(Error):
|
||||
class PKITokenExpected(ForbiddenNotSecurity):
|
||||
message_format = _('The certificates you requested are not available. '
|
||||
'It is likely that this server does not use PKI tokens '
|
||||
'otherwise this is the result of misconfiguration.')
|
||||
code = 403
|
||||
title = 'Forbidden'
|
||||
|
||||
|
||||
class SecurityError(Error):
|
||||
|
|
|
@ -87,9 +87,8 @@ class Manager(manager.Manager):
|
|||
parents_list = self.list_project_parents(project_id)
|
||||
max_depth = CONF.max_project_tree_depth
|
||||
if self._get_hierarchy_depth(parents_list) > max_depth:
|
||||
raise exception.ForbiddenAction(
|
||||
action=_('max hierarchy depth reached for '
|
||||
'%s branch.') % project_id)
|
||||
raise exception.ForbiddenNotSecurity(
|
||||
_('Max hierarchy depth reached for %s branch.') % project_id)
|
||||
|
||||
def _assert_is_domain_project_constraints(self, project_ref, parent_ref):
|
||||
"""Enforces specific constraints of projects that act as domains
|
||||
|
@ -292,9 +291,9 @@ class Manager(manager.Manager):
|
|||
parents_list = self.list_project_parents(project_id)
|
||||
for project in parents_list:
|
||||
if not project.get('enabled', True):
|
||||
raise exception.ForbiddenAction(
|
||||
action=_('cannot enable project %s since it has '
|
||||
'disabled parents') % project_id)
|
||||
raise exception.ForbiddenNotSecurity(
|
||||
_('Cannot enable project %s since it has disabled '
|
||||
'parents') % project_id)
|
||||
|
||||
def _check_whole_subtree_is_disabled(self, project_id, subtree_list=None):
|
||||
if not subtree_list:
|
||||
|
@ -317,8 +316,8 @@ class Manager(manager.Manager):
|
|||
|
||||
parent_id = original_project.get('parent_id')
|
||||
if 'parent_id' in project and project.get('parent_id') != parent_id:
|
||||
raise exception.ForbiddenAction(
|
||||
action=_('Update of `parent_id` is not allowed.'))
|
||||
raise exception.ForbiddenNotSecurity(
|
||||
_('Update of `parent_id` is not allowed.'))
|
||||
|
||||
if ('is_domain' in project and
|
||||
project['is_domain'] != original_project['is_domain']):
|
||||
|
@ -375,9 +374,9 @@ class Manager(manager.Manager):
|
|||
# effectively disables its children.
|
||||
if (not original_project.get('is_domain') and not cascade and not
|
||||
self._check_whole_subtree_is_disabled(project_id)):
|
||||
raise exception.ForbiddenAction(
|
||||
action=_('cannot disable project %(project_id)s since its '
|
||||
'subtree contains enabled projects.')
|
||||
raise exception.ForbiddenNotSecurity(
|
||||
_('Cannot disable project %(project_id)s since its '
|
||||
'subtree contains enabled projects.')
|
||||
% {'project_id': project_id})
|
||||
|
||||
self._disable_project(project_id)
|
||||
|
@ -461,10 +460,10 @@ class Manager(manager.Manager):
|
|||
% project.get('id'))
|
||||
|
||||
if not self.is_leaf_project(project_id) and not cascade:
|
||||
raise exception.ForbiddenAction(
|
||||
action=_('cannot delete the project %s since it is not '
|
||||
'a leaf in the hierarchy. Use the cascade option '
|
||||
'if you want to delete a whole subtree.')
|
||||
raise exception.ForbiddenNotSecurity(
|
||||
_('Cannot delete the project %s since it is not a leaf in the '
|
||||
'hierarchy. Use the cascade option if you want to delete a '
|
||||
'whole subtree.')
|
||||
% project_id)
|
||||
|
||||
if cascade:
|
||||
|
@ -474,9 +473,9 @@ class Manager(manager.Manager):
|
|||
subtree_list.reverse()
|
||||
if not self._check_whole_subtree_is_disabled(
|
||||
project_id, subtree_list=subtree_list):
|
||||
raise exception.ForbiddenAction(
|
||||
action=_('cannot delete project %(project_id)s since its '
|
||||
'subtree contains enabled projects.')
|
||||
raise exception.ForbiddenNotSecurity(
|
||||
_('Cannot delete project %(project_id)s since its subtree '
|
||||
'contains enabled projects.')
|
||||
% {'project_id': project_id})
|
||||
|
||||
project_list = subtree_list + [project]
|
||||
|
@ -705,9 +704,9 @@ class Manager(manager.Manager):
|
|||
# their own domain since, once it is disabled, they won't be able
|
||||
# to get a valid token to issue this delete.
|
||||
if domain['enabled']:
|
||||
raise exception.ForbiddenAction(
|
||||
action=_('cannot delete a domain that is enabled, '
|
||||
'please disable it first.'))
|
||||
raise exception.ForbiddenNotSecurity(
|
||||
_('Cannot delete a domain that is enabled, please disable it '
|
||||
'first.'))
|
||||
|
||||
self._delete_domain_contents(domain_id)
|
||||
# Delete any database stored domain config
|
||||
|
|
|
@ -2974,7 +2974,7 @@ class IdentityTests(AssignmentTestHelperMixin):
|
|||
self.assertFalse(subtree[0]['enabled'])
|
||||
|
||||
parent['enabled'] = True
|
||||
self.assertRaises(exception.ForbiddenAction,
|
||||
self.assertRaises(exception.ForbiddenNotSecurity,
|
||||
self.resource_api.update_project,
|
||||
parent['id'],
|
||||
parent,
|
||||
|
@ -3643,7 +3643,7 @@ class IdentityTests(AssignmentTestHelperMixin):
|
|||
self.resource_api.update_project(project2['id'], project2)
|
||||
|
||||
# Cannot cascade delete root_project, since project1 is enabled
|
||||
self.assertRaises(exception.ForbiddenAction,
|
||||
self.assertRaises(exception.ForbiddenNotSecurity,
|
||||
self.resource_api.delete_project,
|
||||
root_project['id'],
|
||||
cascade=True)
|
||||
|
@ -3671,7 +3671,7 @@ class IdentityTests(AssignmentTestHelperMixin):
|
|||
|
||||
# update the parent_id is not allowed
|
||||
leaf_project['parent_id'] = root_project1['id']
|
||||
self.assertRaises(exception.ForbiddenAction,
|
||||
self.assertRaises(exception.ForbiddenNotSecurity,
|
||||
self.resource_api.update_project,
|
||||
leaf_project['id'],
|
||||
leaf_project)
|
||||
|
@ -3683,7 +3683,7 @@ class IdentityTests(AssignmentTestHelperMixin):
|
|||
root_project1['id'])
|
||||
|
||||
# delete root_project2 is not allowed since it is not a leaf project
|
||||
self.assertRaises(exception.ForbiddenAction,
|
||||
self.assertRaises(exception.ForbiddenNotSecurity,
|
||||
self.resource_api.delete_project,
|
||||
root_project2['id'])
|
||||
|
||||
|
@ -3729,7 +3729,7 @@ class IdentityTests(AssignmentTestHelperMixin):
|
|||
projects_hierarchy = self._create_projects_hierarchy()
|
||||
root_project = projects_hierarchy[0]
|
||||
|
||||
self.assertRaises(exception.ForbiddenAction,
|
||||
self.assertRaises(exception.ForbiddenNotSecurity,
|
||||
self.resource_api.delete_project,
|
||||
root_project['id'])
|
||||
|
||||
|
@ -3744,7 +3744,7 @@ class IdentityTests(AssignmentTestHelperMixin):
|
|||
|
||||
# try to update project3 parent to parent1
|
||||
project3['parent_id'] = project1['id']
|
||||
self.assertRaises(exception.ForbiddenAction,
|
||||
self.assertRaises(exception.ForbiddenNotSecurity,
|
||||
self.resource_api.update_project,
|
||||
project3['id'],
|
||||
project3)
|
||||
|
@ -3779,7 +3779,7 @@ class IdentityTests(AssignmentTestHelperMixin):
|
|||
root_project = projects_hierarchy[0]
|
||||
|
||||
root_project['enabled'] = False
|
||||
self.assertRaises(exception.ForbiddenAction,
|
||||
self.assertRaises(exception.ForbiddenNotSecurity,
|
||||
self.resource_api.update_project,
|
||||
root_project['id'],
|
||||
root_project)
|
||||
|
@ -3798,7 +3798,7 @@ class IdentityTests(AssignmentTestHelperMixin):
|
|||
# Try to enable the leaf project, it's not possible since it has
|
||||
# a disabled parent
|
||||
leaf_project['enabled'] = True
|
||||
self.assertRaises(exception.ForbiddenAction,
|
||||
self.assertRaises(exception.ForbiddenNotSecurity,
|
||||
self.resource_api.update_project,
|
||||
leaf_project['id'],
|
||||
leaf_project)
|
||||
|
@ -3818,7 +3818,7 @@ class IdentityTests(AssignmentTestHelperMixin):
|
|||
# Creating another project in the hierarchy shouldn't be allowed
|
||||
project = unit.new_project_ref(domain_id=DEFAULT_DOMAIN_ID,
|
||||
parent_id=leaf_project['id'])
|
||||
self.assertRaises(exception.ForbiddenAction,
|
||||
self.assertRaises(exception.ForbiddenNotSecurity,
|
||||
self.resource_api.create_project,
|
||||
project['id'],
|
||||
project)
|
||||
|
@ -3863,7 +3863,7 @@ class IdentityTests(AssignmentTestHelperMixin):
|
|||
self.assertDictEqual(domain, domain_ref)
|
||||
|
||||
# Ensure an 'enabled' domain cannot be deleted
|
||||
self.assertRaises(exception.ForbiddenAction,
|
||||
self.assertRaises(exception.ForbiddenNotSecurity,
|
||||
self.resource_api.delete_domain,
|
||||
domain_id=domain['id'])
|
||||
|
||||
|
|
Loading…
Reference in New Issue