Correct RBAC Not Authorized status code

This patch corrects the RBAC "Not Authorized" status code to be 403
instead of 401.
It also switches some strings over to use constants.

Change-Id: I5c2d7384d98720b875de03d311b04193bf448782
This commit is contained in:
Michael Johnson 2017-06-23 17:49:44 -07:00 committed by johnsom
parent 3ccd8a3162
commit 576e63dab5
23 changed files with 134 additions and 108 deletions

View File

@ -36,6 +36,10 @@ the load-balancer API:
It is equivalent to 'rule:context_is_admin or {auth_strategy == noauth}'
if that would be valid syntax.
An alternate policy file has been provided in octavia/etc/policy called
admin_or_owner-policy.json that removes the load-balancer RBAC role
requirement. Please see the README.rst in that directory for more information.
Sample File Generation
----------------------

View File

@ -446,6 +446,9 @@ RBAC_DELETE = 'delete'
RBAC_GET_ONE = 'get_one'
RBAC_GET_ALL = 'get_all'
RBAC_GET_ALL_GLOBAL = 'get_all-global'
RBAC_GET_DEFAULTS = 'get_defaults'
RBAC_GET_STATS = 'get_stats'
RBAC_GET_STATUS = 'get_status'
# PROVIDERS
# TODO(johnsom) When providers are implemented, this should be removed.

View File

@ -70,9 +70,9 @@ class NotFound(APIException):
code = 404
class NotAuthorized(APIException):
msg = _("Not authorized.")
code = 401
class PolicyForbidden(APIException):
msg = _("Policy does not allow this request to be performed.")
code = 403
class InvalidOption(APIException):

View File

@ -67,15 +67,15 @@ class Policy(oslo_policy.Enforcer):
for object creation this should be a dictionary representing the
location of the object e.g.
``{'project_id': context.project_id}``
:param do_raise: if True (the default), raises PolicyNotAuthorized;
:param do_raise: if True (the default), raises PolicyForbidden;
if False, returns False
:param exc: Class of the exceptions to raise if the check fails.
Any remaining arguments passed to :meth:`enforce` (both
positional and keyword arguments) will be passed to
the exceptions class. If not specified,
:class:`PolicyNotAuthorized` will be used.
:class:`PolicyForbidden` will be used.
:raises nova.exceptions.PolicyNotAuthorized: if verification fails
:raises PolicyForbidden: if verification fails
and do_raise is True. Or if 'exc' is specified it will raise an
exceptions of that type.
@ -89,7 +89,7 @@ class Policy(oslo_policy.Enforcer):
credentials['is_admin'] = self.context.is_admin
if not exc:
exc = exceptions.NotAuthorized
exc = exceptions.PolicyForbidden
try:
return super(Policy, self).authorize(

View File

@ -17,28 +17,28 @@ from oslo_policy import policy
rules = [
policy.DocumentedRuleDefault(
'{rbac_obj}{action}'.format(rbac_obj=constants.RBAC_HEALTHMONITOR,
action='get_all'),
action=constants.RBAC_GET_ALL),
constants.RULE_API_READ,
"List Health Monitors of a Pool",
[{'method': 'GET', 'path': '/v2.0/lbaas/healthmonitors'}]
),
policy.DocumentedRuleDefault(
'{rbac_obj}{action}'.format(rbac_obj=constants.RBAC_HEALTHMONITOR,
action='get_all-global'),
action=constants.RBAC_GET_ALL_GLOBAL),
constants.RULE_API_READ_GLOBAL,
"List Health Monitors including resources owned by others",
[{'method': 'GET', 'path': '/v2.0/lbaas/healthmonitors'}]
),
policy.DocumentedRuleDefault(
'{rbac_obj}{action}'.format(rbac_obj=constants.RBAC_HEALTHMONITOR,
action='post'),
action=constants.RBAC_POST),
constants.RULE_API_WRITE,
"Create a Health Monitor",
[{'method': 'POST', 'path': '/v2.0/lbaas/healthmonitors'}]
),
policy.DocumentedRuleDefault(
'{rbac_obj}{action}'.format(rbac_obj=constants.RBAC_HEALTHMONITOR,
action='get_one'),
action=constants.RBAC_GET_ONE),
constants.RULE_API_READ,
"Show Health Monitor details",
[{'method': 'GET',
@ -46,7 +46,7 @@ rules = [
),
policy.DocumentedRuleDefault(
'{rbac_obj}{action}'.format(rbac_obj=constants.RBAC_HEALTHMONITOR,
action='put'),
action=constants.RBAC_PUT),
constants.RULE_API_WRITE,
"Update a Health Monitor",
[{'method': 'PUT',
@ -54,7 +54,7 @@ rules = [
),
policy.DocumentedRuleDefault(
'{rbac_obj}{action}'.format(rbac_obj=constants.RBAC_HEALTHMONITOR,
action='delete'),
action=constants.RBAC_DELETE),
constants.RULE_API_WRITE,
"Remove a Health Monitor",
[{'method': 'DELETE',

View File

@ -17,28 +17,28 @@ from oslo_policy import policy
rules = [
policy.DocumentedRuleDefault(
'{rbac_obj}{action}'.format(rbac_obj=constants.RBAC_L7POLICY,
action='get_all'),
action=constants.RBAC_GET_ALL),
constants.RULE_API_READ,
"List L7 Policys",
[{'method': 'GET', 'path': '/v2.0/lbaas/l7policies'}]
),
policy.DocumentedRuleDefault(
'{rbac_obj}{action}'.format(rbac_obj=constants.RBAC_L7POLICY,
action='get_all-global'),
action=constants.RBAC_GET_ALL_GLOBAL),
constants.RULE_API_READ_GLOBAL,
"List L7 Policys including resources owned by others",
[{'method': 'GET', 'path': '/v2.0/lbaas/l7policies'}]
),
policy.DocumentedRuleDefault(
'{rbac_obj}{action}'.format(rbac_obj=constants.RBAC_L7POLICY,
action='post'),
action=constants.RBAC_POST),
constants.RULE_API_WRITE,
"Create a L7 Policy",
[{'method': 'POST', 'path': '/v2.0/lbaas/l7policies'}]
),
policy.DocumentedRuleDefault(
'{rbac_obj}{action}'.format(rbac_obj=constants.RBAC_L7POLICY,
action='get_one'),
action=constants.RBAC_GET_ONE),
constants.RULE_API_READ,
"Show L7 Policy details",
[{'method': 'GET',
@ -46,7 +46,7 @@ rules = [
),
policy.DocumentedRuleDefault(
'{rbac_obj}{action}'.format(rbac_obj=constants.RBAC_L7POLICY,
action='put'),
action=constants.RBAC_PUT),
constants.RULE_API_WRITE,
"Update a L7 Policy",
[{'method': 'PUT',
@ -54,7 +54,7 @@ rules = [
),
policy.DocumentedRuleDefault(
'{rbac_obj}{action}'.format(rbac_obj=constants.RBAC_L7POLICY,
action='delete'),
action=constants.RBAC_DELETE),
constants.RULE_API_WRITE,
"Remove a L7 Policy",
[{'method': 'DELETE',

View File

@ -17,7 +17,7 @@ from oslo_policy import policy
rules = [
policy.DocumentedRuleDefault(
'{rbac_obj}{action}'.format(rbac_obj=constants.RBAC_L7RULE,
action='get_all'),
action=constants.RBAC_GET_ALL),
constants.RULE_API_READ,
"List L7 Rules",
[{'method': 'GET',
@ -25,7 +25,7 @@ rules = [
),
policy.DocumentedRuleDefault(
'{rbac_obj}{action}'.format(rbac_obj=constants.RBAC_L7RULE,
action='post'),
action=constants.RBAC_POST),
constants.RULE_API_WRITE,
"Create a L7 Rule",
[{'method': 'POST',
@ -33,7 +33,7 @@ rules = [
),
policy.DocumentedRuleDefault(
'{rbac_obj}{action}'.format(rbac_obj=constants.RBAC_L7RULE,
action='get_one'),
action=constants.RBAC_GET_ONE),
constants.RULE_API_READ,
"Show L7 Rule details",
[{'method': 'GET',
@ -41,7 +41,7 @@ rules = [
),
policy.DocumentedRuleDefault(
'{rbac_obj}{action}'.format(rbac_obj=constants.RBAC_L7RULE,
action='put'),
action=constants.RBAC_PUT),
constants.RULE_API_WRITE,
"Update a L7 Rule",
[{'method': 'PUT',
@ -49,7 +49,7 @@ rules = [
),
policy.DocumentedRuleDefault(
'{rbac_obj}{action}'.format(rbac_obj=constants.RBAC_L7RULE,
action='delete'),
action=constants.RBAC_DELETE),
constants.RULE_API_WRITE,
"Remove a L7 Rule",
[{'method': 'DELETE',

View File

@ -17,28 +17,28 @@ from oslo_policy import policy
rules = [
policy.DocumentedRuleDefault(
'{rbac_obj}{action}'.format(rbac_obj=constants.RBAC_LISTENER,
action='get_all'),
action=constants.RBAC_GET_ALL),
constants.RULE_API_READ,
"List Listeners",
[{'method': 'GET', 'path': '/v2.0/lbaas/listeners'}]
),
policy.DocumentedRuleDefault(
'{rbac_obj}{action}'.format(rbac_obj=constants.RBAC_LISTENER,
action='get_all-global'),
action=constants.RBAC_GET_ALL_GLOBAL),
constants.RULE_API_READ_GLOBAL,
"List Listeners including resources owned by others",
[{'method': 'GET', 'path': '/v2.0/lbaas/listeners'}]
),
policy.DocumentedRuleDefault(
'{rbac_obj}{action}'.format(rbac_obj=constants.RBAC_LISTENER,
action='post'),
action=constants.RBAC_POST),
constants.RULE_API_WRITE,
"Create a Listener",
[{'method': 'POST', 'path': '/v2.0/lbaas/listeners'}]
),
policy.DocumentedRuleDefault(
'{rbac_obj}{action}'.format(rbac_obj=constants.RBAC_LISTENER,
action='get_one'),
action=constants.RBAC_GET_ONE),
constants.RULE_API_READ,
"Show Listener details",
[{'method': 'GET',
@ -46,7 +46,7 @@ rules = [
),
policy.DocumentedRuleDefault(
'{rbac_obj}{action}'.format(rbac_obj=constants.RBAC_LISTENER,
action='put'),
action=constants.RBAC_PUT),
constants.RULE_API_WRITE,
"Update a Listener",
[{'method': 'PUT',
@ -54,7 +54,7 @@ rules = [
),
policy.DocumentedRuleDefault(
'{rbac_obj}{action}'.format(rbac_obj=constants.RBAC_LISTENER,
action='delete'),
action=constants.RBAC_DELETE),
constants.RULE_API_WRITE,
"Remove a Listener",
[{'method': 'DELETE',
@ -62,7 +62,7 @@ rules = [
),
policy.DocumentedRuleDefault(
'{rbac_obj}{action}'.format(rbac_obj=constants.RBAC_LISTENER,
action='get_stats'),
action=constants.RBAC_GET_STATS),
constants.RULE_API_READ,
"Show Listener statistics",
[{'method': 'GET',

View File

@ -17,28 +17,28 @@ from oslo_policy import policy
rules = [
policy.DocumentedRuleDefault(
'{rbac_obj}{action}'.format(rbac_obj=constants.RBAC_LOADBALANCER,
action='get_all'),
action=constants.RBAC_GET_ALL),
constants.RULE_API_READ,
"List Load Balancers",
[{'method': 'GET', 'path': '/v2.0/lbaas/loadbalancers'}]
),
policy.DocumentedRuleDefault(
'{rbac_obj}{action}'.format(rbac_obj=constants.RBAC_LOADBALANCER,
action='get_all-global'),
action=constants.RBAC_GET_ALL_GLOBAL),
constants.RULE_API_READ_GLOBAL,
"List Load Balancers including resources owned by others",
[{'method': 'GET', 'path': '/v2.0/lbaas/loadbalancers'}]
),
policy.DocumentedRuleDefault(
'{rbac_obj}{action}'.format(rbac_obj=constants.RBAC_LOADBALANCER,
action='post'),
action=constants.RBAC_POST),
constants.RULE_API_WRITE,
"Create a Load Balancer",
[{'method': 'POST', 'path': '/v2.0/lbaas/loadbalancers'}]
),
policy.DocumentedRuleDefault(
'{rbac_obj}{action}'.format(rbac_obj=constants.RBAC_LOADBALANCER,
action='get_one'),
action=constants.RBAC_GET_ONE),
constants.RULE_API_READ,
"Show Load Balancer details",
[{'method': 'GET',
@ -46,7 +46,7 @@ rules = [
),
policy.DocumentedRuleDefault(
'{rbac_obj}{action}'.format(rbac_obj=constants.RBAC_LOADBALANCER,
action='put'),
action=constants.RBAC_PUT),
constants.RULE_API_WRITE,
"Update a Load Balancer",
[{'method': 'PUT',
@ -54,7 +54,7 @@ rules = [
),
policy.DocumentedRuleDefault(
'{rbac_obj}{action}'.format(rbac_obj=constants.RBAC_LOADBALANCER,
action='delete'),
action=constants.RBAC_DELETE),
constants.RULE_API_WRITE,
"Remove a Load Balancer",
[{'method': 'DELETE',
@ -62,7 +62,7 @@ rules = [
),
policy.DocumentedRuleDefault(
'{rbac_obj}{action}'.format(rbac_obj=constants.RBAC_LOADBALANCER,
action='get_stats'),
action=constants.RBAC_GET_STATS),
constants.RULE_API_READ,
"Show Load Balancer statistics",
[{'method': 'GET',
@ -70,7 +70,7 @@ rules = [
),
policy.DocumentedRuleDefault(
'{rbac_obj}{action}'.format(rbac_obj=constants.RBAC_LOADBALANCER,
action='get_status'),
action=constants.RBAC_GET_STATUS),
constants.RULE_API_READ,
"Show Load Balancer status",
[{'method': 'GET',

View File

@ -17,21 +17,21 @@ from oslo_policy import policy
rules = [
policy.DocumentedRuleDefault(
'{rbac_obj}{action}'.format(rbac_obj=constants.RBAC_MEMBER,
action='get_all'),
action=constants.RBAC_GET_ALL),
constants.RULE_API_READ,
"List Members of a Pool",
[{'method': 'GET', 'path': '/v2.0/lbaas/pools/{pool_id}/members'}]
),
policy.DocumentedRuleDefault(
'{rbac_obj}{action}'.format(rbac_obj=constants.RBAC_MEMBER,
action='post'),
action=constants.RBAC_POST),
constants.RULE_API_WRITE,
"Create a Member",
[{'method': 'POST', 'path': '/v2.0/lbaas/pools/{pool_id}/members'}]
),
policy.DocumentedRuleDefault(
'{rbac_obj}{action}'.format(rbac_obj=constants.RBAC_MEMBER,
action='get_one'),
action=constants.RBAC_GET_ONE),
constants.RULE_API_READ,
"Show Member details",
[{'method': 'GET',
@ -39,7 +39,7 @@ rules = [
),
policy.DocumentedRuleDefault(
'{rbac_obj}{action}'.format(rbac_obj=constants.RBAC_MEMBER,
action='put'),
action=constants.RBAC_PUT),
constants.RULE_API_WRITE,
"Update a Member",
[{'method': 'PUT',
@ -47,7 +47,7 @@ rules = [
),
policy.DocumentedRuleDefault(
'{rbac_obj}{action}'.format(rbac_obj=constants.RBAC_MEMBER,
action='delete'),
action=constants.RBAC_DELETE),
constants.RULE_API_WRITE,
"Remove a Member",
[{'method': 'DELETE',

View File

@ -17,28 +17,28 @@ from oslo_policy import policy
rules = [
policy.DocumentedRuleDefault(
'{rbac_obj}{action}'.format(rbac_obj=constants.RBAC_POOL,
action='get_all'),
action=constants.RBAC_GET_ALL),
constants.RULE_API_READ,
"List Pools",
[{'method': 'GET', 'path': '/v2.0/lbaas/pools'}]
),
policy.DocumentedRuleDefault(
'{rbac_obj}{action}'.format(rbac_obj=constants.RBAC_POOL,
action='get_all-global'),
action=constants.RBAC_GET_ALL_GLOBAL),
constants.RULE_API_READ_GLOBAL,
"List Pools including resources owned by others",
[{'method': 'GET', 'path': '/v2.0/lbaas/pools'}]
),
policy.DocumentedRuleDefault(
'{rbac_obj}{action}'.format(rbac_obj=constants.RBAC_POOL,
action='post'),
action=constants.RBAC_POST),
constants.RULE_API_WRITE,
"Create a Pool",
[{'method': 'POST', 'path': '/v2.0/lbaas/pools'}]
),
policy.DocumentedRuleDefault(
'{rbac_obj}{action}'.format(rbac_obj=constants.RBAC_POOL,
action='get_one'),
action=constants.RBAC_GET_ONE),
constants.RULE_API_READ,
"Show Pool details",
[{'method': 'GET',
@ -46,7 +46,7 @@ rules = [
),
policy.DocumentedRuleDefault(
'{rbac_obj}{action}'.format(rbac_obj=constants.RBAC_POOL,
action='put'),
action=constants.RBAC_PUT),
constants.RULE_API_WRITE,
"Update a Pool",
[{'method': 'PUT',
@ -54,7 +54,7 @@ rules = [
),
policy.DocumentedRuleDefault(
'{rbac_obj}{action}'.format(rbac_obj=constants.RBAC_POOL,
action='delete'),
action=constants.RBAC_DELETE),
constants.RULE_API_WRITE,
"Remove a Pool",
[{'method': 'DELETE',

View File

@ -17,21 +17,21 @@ from oslo_policy import policy
rules = [
policy.DocumentedRuleDefault(
'{rbac_obj}{action}'.format(rbac_obj=constants.RBAC_QUOTA,
action='get_all'),
action=constants.RBAC_GET_ALL),
constants.RULE_API_READ_QUOTA,
"List Quotas",
[{'method': 'GET', 'path': '/v2.0/lbaas/quotas'}]
),
policy.DocumentedRuleDefault(
'{rbac_obj}{action}'.format(rbac_obj=constants.RBAC_QUOTA,
action='get_all-global'),
action=constants.RBAC_GET_ALL_GLOBAL),
constants.RULE_API_READ_QUOTA_GLOBAL,
"List Quotas including resources owned by others",
[{'method': 'GET', 'path': '/v2.0/lbaas/quotas'}]
),
policy.DocumentedRuleDefault(
'{rbac_obj}{action}'.format(rbac_obj=constants.RBAC_QUOTA,
action='get_one'),
action=constants.RBAC_GET_ONE),
constants.RULE_API_READ_QUOTA,
"Show Quota details",
[{'method': 'GET',
@ -39,7 +39,7 @@ rules = [
),
policy.DocumentedRuleDefault(
'{rbac_obj}{action}'.format(rbac_obj=constants.RBAC_QUOTA,
action='put'),
action=constants.RBAC_PUT),
constants.RULE_API_WRITE_QUOTA,
"Update a Quota",
[{'method': 'PUT',
@ -47,7 +47,7 @@ rules = [
),
policy.DocumentedRuleDefault(
'{rbac_obj}{action}'.format(rbac_obj=constants.RBAC_QUOTA,
action='delete'),
action=constants.RBAC_DELETE),
constants.RULE_API_WRITE_QUOTA,
"Remove a Quota",
[{'method': 'DELETE',
@ -55,7 +55,7 @@ rules = [
),
policy.DocumentedRuleDefault(
'{rbac_obj}{action}'.format(rbac_obj=constants.RBAC_QUOTA,
action='get_defaults'),
action=constants.RBAC_GET_DEFAULTS),
constants.RULE_API_READ_QUOTA,
"Show Default Quota for a Project",
[{'method': 'GET',

View File

@ -63,8 +63,9 @@ class BaseAPITest(base_db_test.OctaviaDBTestBase):
QUOTA_PATH = QUOTAS_PATH + '/{project_id}'
QUOTA_DEFAULT_PATH = QUOTAS_PATH + '/{project_id}/default'
NOT_AUTHORIZED_BODY = {'debuginfo': None, 'faultcode': 'Client',
'faultstring': 'Not authorized.'}
NOT_AUTHORIZED_BODY = {
'debuginfo': None, 'faultcode': 'Client',
'faultstring': 'Policy does not allow this request to be performed.'}
def setUp(self):
super(BaseAPITest, self).setUp()

View File

@ -122,7 +122,7 @@ class TestHealthMonitor(base.BaseAPITest):
with mock.patch.object(octavia.common.context.Context, 'project_id',
uuidutils.generate_uuid()):
response = self.get(self.HM_PATH.format(
healthmonitor_id=api_hm.get('id')), status=401)
healthmonitor_id=api_hm.get('id')), status=403)
self.conf.config(group='api_settings', auth_strategy=auth_strategy)
self.assertEqual(self.NOT_AUTHORIZED_BODY, response.json)
@ -164,7 +164,7 @@ class TestHealthMonitor(base.BaseAPITest):
self.conf.config(group='api_settings', auth_strategy=constants.TESTING)
with mock.patch.object(octavia.common.context.Context, 'project_id',
uuidutils.generate_uuid()):
hms = self.get(self.HMS_PATH, status=401).json
hms = self.get(self.HMS_PATH, status=403).json
self.conf.config(group='api_settings', auth_strategy=auth_strategy)
self.assertEqual(self.NOT_AUTHORIZED_BODY, hms)
@ -652,7 +652,7 @@ class TestHealthMonitor(base.BaseAPITest):
uuidutils.generate_uuid()):
api_hm = self.create_health_monitor(
self.pool_id, constants.HEALTH_MONITOR_HTTP,
1, 1, 1, 1, status=401)
1, 1, 1, 1, status=403)
self.conf.config(group='api_settings', auth_strategy=auth_strategy)
self.assertEqual(self.NOT_AUTHORIZED_BODY, api_hm)
@ -814,7 +814,7 @@ class TestHealthMonitor(base.BaseAPITest):
uuidutils.generate_uuid()):
response = self.put(
self.HM_PATH.format(healthmonitor_id=api_hm.get('id')),
self._build_body(new_hm), status=401)
self._build_body(new_hm), status=403)
self.conf.config(group='api_settings', auth_strategy=auth_strategy)
self.assertEqual(self.NOT_AUTHORIZED_BODY, response.json)
@ -937,7 +937,7 @@ class TestHealthMonitor(base.BaseAPITest):
uuidutils.generate_uuid()):
self.delete(
self.HM_PATH.format(healthmonitor_id=api_hm.get('id')),
status=401)
status=403)
self.conf.config(group='api_settings', auth_strategy=auth_strategy)
self.assert_correct_status(
lb_id=self.lb_id, listener_id=self.listener_id,

View File

@ -98,7 +98,7 @@ class TestL7Policy(base.BaseAPITest):
with mock.patch.object(octavia.common.context.Context, 'project_id',
uuidutils.generate_uuid()):
response = self.get(self.L7POLICY_PATH.format(
l7policy_id=api_l7policy.get('id')), status=401)
l7policy_id=api_l7policy.get('id')), status=403)
self.conf.config(group='api_settings', auth_strategy=auth_strategy)
self.assertEqual(self.NOT_AUTHORIZED_BODY, response.json)
@ -294,7 +294,7 @@ class TestL7Policy(base.BaseAPITest):
self.conf.config(group='api_settings', auth_strategy=constants.TESTING)
with mock.patch.object(octavia.common.context.Context, 'project_id',
uuidutils.generate_uuid()):
policies = self.get(self.L7POLICIES_PATH, status=401).json
policies = self.get(self.L7POLICIES_PATH, status=403).json
self.conf.config(group='api_settings', auth_strategy=auth_strategy)
self.assertEqual(self.NOT_AUTHORIZED_BODY, policies)
@ -548,7 +548,7 @@ class TestL7Policy(base.BaseAPITest):
self.project_id):
api_l7policy = self.create_l7policy(
self.listener_id,
constants.L7POLICY_ACTION_REJECT, status=401)
constants.L7POLICY_ACTION_REJECT, status=403)
self.conf.config(group='api_settings', auth_strategy=auth_strategy)
self.assertEqual(self.NOT_AUTHORIZED_BODY, api_l7policy)
@ -706,7 +706,7 @@ class TestL7Policy(base.BaseAPITest):
self.project_id):
response = self.put(self.L7POLICY_PATH.format(
l7policy_id=api_l7policy.get('id')),
self._build_body(new_l7policy), status=401)
self._build_body(new_l7policy), status=403)
self.conf.config(group='api_settings', auth_strategy=auth_strategy)
self.assertEqual(self.NOT_AUTHORIZED_BODY, response.json)
@ -898,7 +898,7 @@ class TestL7Policy(base.BaseAPITest):
with mock.patch.object(octavia.common.context.Context, 'project_id',
uuidutils.generate_uuid()):
self.delete(self.L7POLICY_PATH.format(
l7policy_id=api_l7policy.get('id')), status=401)
l7policy_id=api_l7policy.get('id')), status=403)
self.conf.config(group='api_settings', auth_strategy=auth_strategy)
self.assert_correct_status(

View File

@ -97,7 +97,7 @@ class TestL7Rule(base.BaseAPITest):
with mock.patch.object(octavia.common.context.Context, 'project_id',
self.project_id):
response = self.get(self.l7rule_path.format(
l7rule_id=l7rule.get('id')), status=401).json
l7rule_id=l7rule.get('id')), status=403).json
self.conf.config(group='api_settings', auth_strategy=auth_strategy)
self.assertEqual(self.NOT_AUTHORIZED_BODY, response)
@ -207,7 +207,7 @@ class TestL7Rule(base.BaseAPITest):
self.conf.config(group='api_settings', auth_strategy=constants.TESTING)
with mock.patch.object(octavia.common.context.Context, 'project_id',
self.project_id):
rules = self.get(self.l7rules_path, status=401)
rules = self.get(self.l7rules_path, status=403)
self.conf.config(group='api_settings', auth_strategy=auth_strategy)
self.assertEqual(self.NOT_AUTHORIZED_BODY, rules.json)
@ -419,7 +419,7 @@ class TestL7Rule(base.BaseAPITest):
api_l7rule = self.create_l7rule(
self.l7policy_id, constants.L7RULE_TYPE_HOST_NAME,
constants.L7RULE_COMPARE_TYPE_EQUAL_TO,
'www.example.com', status=401)
'www.example.com', status=403)
self.conf.config(group='api_settings', auth_strategy=auth_strategy)
self.assertEqual(self.NOT_AUTHORIZED_BODY, api_l7rule)
@ -637,7 +637,7 @@ class TestL7Rule(base.BaseAPITest):
self.project_id):
response = self.put(self.l7rule_path.format(
l7rule_id=api_l7rule.get('id')),
self._build_body(new_l7rule), status=401)
self._build_body(new_l7rule), status=403)
self.conf.config(group='api_settings', auth_strategy=auth_strategy)
self.assertEqual(self.NOT_AUTHORIZED_BODY, response.json)
self.assert_correct_status(
@ -787,7 +787,7 @@ class TestL7Rule(base.BaseAPITest):
self.project_id):
self.delete(
self.l7rule_path.format(l7rule_id=api_l7rule.get('id')),
status=401)
status=403)
self.conf.config(group='api_settings', auth_strategy=auth_strategy)
self.assert_correct_status(
lb_id=self.lb_id, listener_id=self.listener_id,

View File

@ -189,7 +189,7 @@ class TestListener(base.BaseAPITest):
auth_strategy=constants.KEYSTONE)
with mock.patch.object(octavia.common.context.Context, 'project_id',
uuidutils.generate_uuid()):
listeners = self.get(self.LISTENERS_PATH, status=401).json
listeners = self.get(self.LISTENERS_PATH, status=403).json
self.conf.config(group='api_settings', auth_strategy=auth_strategy)
self.assertEqual(self.NOT_AUTHORIZED_BODY, listeners)
@ -402,7 +402,7 @@ class TestListener(base.BaseAPITest):
with mock.patch.object(octavia.common.context.Context, 'project_id',
uuidutils.generate_uuid()):
response = self.get(self.listener_path.format(
listener_id=listener['id']), status=401)
listener_id=listener['id']), status=403)
self.conf.config(group='api_settings', auth_strategy=auth_strategy)
self.assertEqual(self.NOT_AUTHORIZED_BODY, response.json)
@ -650,7 +650,7 @@ class TestListener(base.BaseAPITest):
with mock.patch.object(octavia.common.context.Context, 'project_id',
uuidutils.generate_uuid()):
response = self.post(self.LISTENERS_PATH, body, status=401)
response = self.post(self.LISTENERS_PATH, body, status=403)
self.conf.config(group='api_settings', auth_strategy=auth_strategy)
self.assertEqual(self.NOT_AUTHORIZED_BODY, response.json)
@ -816,7 +816,7 @@ class TestListener(base.BaseAPITest):
auth_strategy=constants.TESTING)
with mock.patch.object(octavia.common.context.Context, 'project_id',
uuidutils.generate_uuid()):
api_listener = self.put(listener_path, body, status=401)
api_listener = self.put(listener_path, body, status=403)
self.conf.config(group='api_settings', auth_strategy=auth_strategy)
self.assertEqual(self.NOT_AUTHORIZED_BODY, api_listener.json)
self.assert_correct_lb_status(self.lb_id, constants.ONLINE,
@ -919,7 +919,7 @@ class TestListener(base.BaseAPITest):
self.conf.config(group='api_settings', auth_strategy=constants.TESTING)
with mock.patch.object(octavia.common.context.Context, 'project_id',
uuidutils.generate_uuid()):
self.delete(listener_path, status=401)
self.delete(listener_path, status=403)
self.conf.config(group='api_settings', auth_strategy=auth_strategy)
self.assert_correct_lb_status(self.lb_id, constants.ONLINE,
constants.ACTIVE)

View File

@ -391,7 +391,7 @@ class TestLoadBalancer(base.BaseAPITest):
body = self._build_body(lb_json)
with mock.patch.object(octavia.common.context.Context, 'project_id',
uuidutils.generate_uuid()):
response = self.post(self.LBS_PATH, body, status=401)
response = self.post(self.LBS_PATH, body, status=403)
api_lb = response.json
self.conf.config(group='api_settings', auth_strategy=auth_strategy)
self.assertEqual(self.NOT_AUTHORIZED_BODY, api_lb)
@ -550,7 +550,7 @@ class TestLoadBalancer(base.BaseAPITest):
LB_PROJECT_PATH = '{}?project_id={}'.format(self.LBS_PATH, project_id)
with mock.patch.object(octavia.common.context.Context, 'project_id',
self.project_id):
response = self.get(LB_PROJECT_PATH, status=401)
response = self.get(LB_PROJECT_PATH, status=403)
api_lb = response.json
self.conf.config(group='api_settings', auth_strategy=auth_strategy)
self.assertEqual(self.NOT_AUTHORIZED_BODY, api_lb)
@ -826,7 +826,7 @@ class TestLoadBalancer(base.BaseAPITest):
with mock.patch.object(octavia.common.context.Context, 'project_id',
uuidutils.generate_uuid()):
response = self.get(self.LB_PATH.format(lb_id=lb_dict.get('id')),
status=401)
status=403)
api_lb = response.json
self.conf.config(group='api_settings', auth_strategy=auth_strategy)
self.assertEqual(self.NOT_AUTHORIZED_BODY, api_lb)
@ -954,7 +954,7 @@ class TestLoadBalancer(base.BaseAPITest):
with mock.patch.object(octavia.common.context.Context, 'project_id',
uuidutils.generate_uuid()):
response = self.put(self.LB_PATH.format(lb_id=lb_dict.get('id')),
lb_json, status=401)
lb_json, status=403)
api_lb = response.json
self.conf.config(group='api_settings', auth_strategy=auth_strategy)
self.assertEqual(self.NOT_AUTHORIZED_BODY, api_lb)
@ -1111,7 +1111,7 @@ class TestLoadBalancer(base.BaseAPITest):
with mock.patch.object(octavia.common.context.Context, 'project_id',
uuidutils.generate_uuid()):
self.delete(self.LB_PATH.format(lb_id=lb_dict.get('id')),
status=401)
status=403)
self.conf.config(group='api_settings', auth_strategy=auth_strategy)
response = self.get(self.LB_PATH.format(lb_id=lb_dict.get('id')))

View File

@ -108,7 +108,7 @@ class TestMember(base.BaseAPITest):
with mock.patch.object(octavia.common.context.Context, 'project_id',
uuidutils.generate_uuid()):
response = self.get(self.member_path.format(
member_id=api_member.get('id')), status=401).json
member_id=api_member.get('id')), status=403).json
self.conf.config(group='api_settings', auth_strategy=auth_strategy)
self.assertEqual(self.NOT_AUTHORIZED_BODY, response)
@ -215,7 +215,7 @@ class TestMember(base.BaseAPITest):
self.conf.config(group='api_settings', auth_strategy=constants.TESTING)
with mock.patch.object(octavia.common.context.Context, 'project_id',
uuidutils.generate_uuid()):
response = self.get(self.members_path, status=401)
response = self.get(self.members_path, status=403)
self.conf.config(group='api_settings', auth_strategy=auth_strategy)
self.assertEqual(self.NOT_AUTHORIZED_BODY, response.json)
@ -398,7 +398,7 @@ class TestMember(base.BaseAPITest):
with mock.patch.object(octavia.common.context.Context, 'project_id',
self.project_id):
api_member = self.create_member(
self.pool_id, '10.0.0.1', 80, status=401)
self.pool_id, '10.0.0.1', 80, status=403)
self.conf.config(group='api_settings', auth_strategy=auth_strategy)
self.assertEqual(self.NOT_AUTHORIZED_BODY, api_member)
@ -627,7 +627,7 @@ class TestMember(base.BaseAPITest):
member_id=api_member.get('id'))
response = self.put(
member_path,
self._build_body(new_member), status=401)
self._build_body(new_member), status=403)
self.conf.config(group='api_settings', auth_strategy=auth_strategy)
self.assertEqual(self.NOT_AUTHORIZED_BODY, response.json)
@ -789,7 +789,7 @@ class TestMember(base.BaseAPITest):
with mock.patch.object(octavia.common.context.Context, 'project_id',
self.project_id):
self.delete(self.member_path_listener.format(
member_id=api_member.get('id')), status=401)
member_id=api_member.get('id')), status=403)
self.conf.config(group='api_settings', auth_strategy=auth_strategy)
self.assert_correct_status(

View File

@ -122,7 +122,7 @@ class TestPool(base.BaseAPITest):
with mock.patch.object(octavia.common.context.Context, 'project_id',
uuidutils.generate_uuid()):
response = self.get(self.POOL_PATH.format(
pool_id=api_pool.get('id')), status=401)
pool_id=api_pool.get('id')), status=403)
self.conf.config(group='api_settings', auth_strategy=auth_strategy)
self.assertEqual(self.NOT_AUTHORIZED_BODY, response.json)
@ -308,7 +308,7 @@ class TestPool(base.BaseAPITest):
self.conf.config(group='api_settings', auth_strategy=constants.TESTING)
with mock.patch.object(octavia.common.context.Context, 'project_id',
uuidutils.generate_uuid()):
pools = self.get(self.POOLS_PATH, status=401).json
pools = self.get(self.POOLS_PATH, status=403).json
self.conf.config(group='api_settings', auth_strategy=auth_strategy)
self.assertEqual(self.NOT_AUTHORIZED_BODY, pools)
@ -592,7 +592,7 @@ class TestPool(base.BaseAPITest):
self.lb_id,
constants.PROTOCOL_HTTP,
constants.LB_ALGORITHM_ROUND_ROBIN,
listener_id=self.listener_id, status=401)
listener_id=self.listener_id, status=403)
self.conf.config(group='api_settings', auth_strategy=auth_strategy)
self.assertEqual(self.NOT_AUTHORIZED_BODY, api_pool)
@ -834,7 +834,7 @@ class TestPool(base.BaseAPITest):
uuidutils.generate_uuid()):
api_pool = self.put(
self.POOL_PATH.format(pool_id=api_pool.get('id')),
self._build_body(new_pool), status=401)
self._build_body(new_pool), status=403)
self.conf.config(group='api_settings', auth_strategy=auth_strategy)
self.assertEqual(self.NOT_AUTHORIZED_BODY, api_pool.json)
@ -967,7 +967,7 @@ class TestPool(base.BaseAPITest):
with mock.patch.object(octavia.common.context.Context, 'project_id',
uuidutils.generate_uuid()):
self.delete(self.POOL_PATH.format(pool_id=api_pool.get('id')),
status=401)
status=403)
self.conf.config(group='api_settings', auth_strategy=auth_strategy)
self.assert_correct_status(

View File

@ -118,7 +118,7 @@ class TestQuotas(base.BaseAPITest):
self.conf.config(group='api_settings', auth_strategy=constants.TESTING)
with mock.patch.object(octavia.common.context.Context, 'project_id',
uuidutils.generate_uuid()):
response = self.get(self.QUOTAS_PATH, status=401)
response = self.get(self.QUOTAS_PATH, status=403)
self.conf.config(group='api_settings', auth_strategy=auth_strategy)
self.assertEqual(self.NOT_AUTHORIZED_BODY, response.json)
@ -150,7 +150,7 @@ class TestQuotas(base.BaseAPITest):
with mock.patch(
"oslo_context.context.RequestContext.to_policy_values",
return_value=override_credentials):
response = self.get(self.QUOTAS_PATH, status=401)
response = self.get(self.QUOTAS_PATH, status=403)
self.conf.config(group='api_settings', auth_strategy=auth_strategy)
self.assertEqual(self.NOT_AUTHORIZED_BODY, response.json)
@ -188,7 +188,7 @@ class TestQuotas(base.BaseAPITest):
with mock.patch(
"oslo_context.context.RequestContext.to_policy_values",
return_value=override_credentials):
response = self.get(self.QUOTAS_PATH, status=401)
response = self.get(self.QUOTAS_PATH, status=403)
self.conf.config(group='api_settings', auth_strategy=auth_strategy)
self.assertEqual(self.NOT_AUTHORIZED_BODY, response.json)
@ -474,7 +474,7 @@ class TestQuotas(base.BaseAPITest):
with mock.patch.object(octavia.common.context.Context, 'project_id',
uuidutils.generate_uuid()):
quotas = self.get(self.QUOTA_PATH.format(project_id=project1_id),
status=401)
status=403)
self.conf.config(group='api_settings', auth_strategy=auth_strategy)
self.assertEqual(self.NOT_AUTHORIZED_BODY, quotas.json)
@ -507,7 +507,7 @@ class TestQuotas(base.BaseAPITest):
return_value=override_credentials):
quotas = self.get(
self.QUOTA_PATH.format(project_id=project1_id),
status=401)
status=403)
self.conf.config(group='api_settings', auth_strategy=auth_strategy)
self.assertEqual(self.NOT_AUTHORIZED_BODY, quotas.json)
@ -540,7 +540,7 @@ class TestQuotas(base.BaseAPITest):
return_value=override_credentials):
quotas = self.get(
self.QUOTA_PATH.format(project_id=project1_id),
status=401)
status=403)
self.conf.config(group='api_settings', auth_strategy=auth_strategy)
self.assertEqual(self.NOT_AUTHORIZED_BODY, quotas.json)
@ -659,7 +659,7 @@ class TestQuotas(base.BaseAPITest):
with mock.patch.object(octavia.common.context.Context, 'project_id',
uuidutils.generate_uuid()):
response = self.get(self.QUOTA_DEFAULT_PATH.format(
project_id=self.project_id), status=401)
project_id=self.project_id), status=403)
self.assertEqual(self.NOT_AUTHORIZED_BODY, response.json)
self.conf.config(group='api_settings', auth_strategy=auth_strategy)
@ -728,7 +728,7 @@ class TestQuotas(base.BaseAPITest):
with mock.patch(
"oslo_context.context.RequestContext.to_policy_values",
return_value=override_credentials):
response = self.put(quota_path, body, status=401)
response = self.put(quota_path, body, status=403)
self.conf.config(group='api_settings', auth_strategy=auth_strategy)
self.assertEqual(self.NOT_AUTHORIZED_BODY, response.json)
@ -837,7 +837,7 @@ class TestQuotas(base.BaseAPITest):
with mock.patch(
"oslo_context.context.RequestContext.to_policy_values",
return_value=override_credentials):
self.delete(quota_path, status=401)
self.delete(quota_path, status=403)
self.conf.config(group='api_settings', auth_strategy=auth_strategy)
response = self.get(quota_path)
quota_dict = response.json

View File

@ -55,7 +55,7 @@ class PolicyFileTestCase(base.TestCase):
tmp.write('{"example:test": "!"}')
tmp.flush()
self.context.policy.load_rules(True)
self.assertRaises(exceptions.NotAuthorized,
self.assertRaises(exceptions.PolicyForbidden,
self.context.policy.authorize,
action, self.target)
@ -99,7 +99,7 @@ class PolicyTestCase(base.TestCase):
def test_authorize_bad_action_throws(self):
action = "example:denied"
self.assertRaises(
exceptions.NotAuthorized, self.context.policy.authorize,
exceptions.PolicyForbidden, self.context.policy.authorize,
action, self.target)
def test_authorize_bad_action_noraise(self):
@ -116,7 +116,7 @@ class PolicyTestCase(base.TestCase):
def test_authorize_http(self, req_mock):
req_mock.post('http://www.example.com/', text='False')
action = "example:get_http"
self.assertRaises(exceptions.NotAuthorized,
self.assertRaises(exceptions.PolicyForbidden,
self.context.policy.authorize, action, self.target)
def test_templatized_authorization(self):
@ -125,13 +125,13 @@ class PolicyTestCase(base.TestCase):
action = "example:my_file"
self.context.policy.authorize(action, target_mine)
self.assertRaises(exceptions.NotAuthorized,
self.assertRaises(exceptions.PolicyForbidden,
self.context.policy.authorize,
action, target_not_mine)
def test_early_AND_authorization(self):
action = "example:early_and_fail"
self.assertRaises(exceptions.NotAuthorized,
self.assertRaises(exceptions.PolicyForbidden,
self.context.policy.authorize, action, self.target)
def test_early_OR_authorization(self):
@ -228,5 +228,5 @@ class AdminRolePolicyTestCase(base.TestCase):
"""
for action in self.actions:
self.assertRaises(
exceptions.NotAuthorized, self.context.policy.authorize,
exceptions.PolicyForbidden, self.context.policy.authorize,
action, self.target)

View File

@ -0,0 +1,18 @@
---
features:
- |
The Octavia v2 API now supports Role Based Access Control (RBAC).
The default rules require users to have a load-balancer_* role to be
able to access the Octavia v2 API. This can be overriden with the
admin_or_owner-policy.json sample file provided.
See the `Octavia Policies
<https://docs.openstack.org/developer/octavia/main/policy.html>`_
document for more information.
security:
- |
Note that while the Octavia v2 API now supports Role Bassed Access
Control (RBAC), the Octavia v1.0 API does not. The Octavia v1.0 API
should not be exposed publicly and should only be used internally
such as for the neutron-lbaas octavia driver. Publicly accessible
instances of the Octavia API should have the v1.0 API disabled via the
Octavia configuration file.