Fix support for scoped tokens and default roles

This patch is the base patch to enable support for Keystone
scoped tokens[1] and default roles[2] in the Designate API.

It also migrates to using project_id in the context objects instead of
the deprecated tenant_id.

[1] https://docs.openstack.org/keystone/latest/admin/tokens-overview.html#authorization-scopes
[2] https://docs.openstack.org/keystone/latest/admin/service-api-protection.html

Depends-On: https://review.opendev.org/c/openstack/designate-tempest-plugin/+/821632

Change-Id: I43bb76dc4dc1d167d86fd5ea139a50f95f3b0b4a
This commit is contained in:
Michael Johnson 2021-07-13 21:24:52 +00:00
parent aa798fc006
commit 5f87d207b4
26 changed files with 861 additions and 317 deletions

View File

@ -54,6 +54,24 @@
Functional testing for a FIPS enabled Centos 8 stream system Functional testing for a FIPS enabled Centos 8 stream system
pre-run: playbooks/enable-fips.yaml pre-run: playbooks/enable-fips.yaml
- job:
name: designate-bind9-scoped-tokens
post-run: playbooks/designate-bind9/post.yaml
parent: designate-base
vars:
devstack_local_conf:
post-config:
$DESIGNATE_CONF:
oslo_policy:
enforce_scope: True
enforce_new_defaults: True
test-config:
"$TEMPEST_CONFIG":
enforce_scope:
designate: True
dns_feature_enabled:
enforce_new_defaults: True
- job: - job:
name: designate-pdns4 name: designate-pdns4
post-run: playbooks/designate-pdns4/post.yaml post-run: playbooks/designate-pdns4/post.yaml
@ -136,6 +154,7 @@
- designate-bind9 - designate-bind9
- designate-bind9-centos8stream-fips: - designate-bind9-centos8stream-fips:
voting: false voting: false
- designate-bind9-scoped-tokens
- designate-pdns4 - designate-pdns4
- designate-grenade-pdns4 - designate-grenade-pdns4
- designate-ipv6-only-pdns4 - designate-ipv6-only-pdns4
@ -145,6 +164,7 @@
queue: designate queue: designate
jobs: jobs:
- designate-bind9 - designate-bind9
- designate-bind9-scoped-tokens
- designate-pdns4 - designate-pdns4
- designate-grenade-pdns4 - designate-grenade-pdns4
- designate-ipv6-only-pdns4 - designate-ipv6-only-pdns4

View File

@ -128,14 +128,13 @@ class KeystoneContextMiddleware(ContextMiddleware):
pass pass
tenant_id = headers.get('X-Tenant-ID') tenant_id = headers.get('X-Tenant-ID')
if tenant_id is None:
return flask.Response(status=401)
catalog = None catalog = None
if headers.get('X-Service-Catalog'): if headers.get('X-Service-Catalog'):
catalog = jsonutils.loads(headers.get('X-Service-Catalog')) catalog = jsonutils.loads(headers.get('X-Service-Catalog'))
roles = headers.get('X-Roles').split(',') roles = headers.get('X-Roles').split(',')
system_scope = headers.get('Openstack-System-Scope')
try: try:
self.make_context( self.make_context(
@ -144,7 +143,8 @@ class KeystoneContextMiddleware(ContextMiddleware):
user_id=headers.get('X-User-ID'), user_id=headers.get('X-User-ID'),
project_id=tenant_id, project_id=tenant_id,
roles=roles, roles=roles,
service_catalog=catalog service_catalog=catalog,
system_scope=system_scope
) )
except exceptions.Forbidden: except exceptions.Forbidden:
return flask.Response(status=403) return flask.Response(status=403)

View File

@ -17,6 +17,7 @@ from oslo_log import log as logging
import pecan import pecan
from designate.api.v2.controllers import rest from designate.api.v2.controllers import rest
from designate.common import constants
from designate import exceptions from designate import exceptions
from designate.objects.adapters import DesignateAdapter from designate.objects.adapters import DesignateAdapter
from designate import policy from designate import policy
@ -31,7 +32,11 @@ class ZoneExportController(rest.RestController):
@utils.validate_uuid('export_id') @utils.validate_uuid('export_id')
def get_all(self, export_id): def get_all(self, export_id):
context = pecan.request.environ['context'] context = pecan.request.environ['context']
if policy.enforce_new_defaults():
target = {constants.RBAC_PROJECT_ID: context.project_id}
else:
target = {'tenant_id': context.project_id} target = {'tenant_id': context.project_id}
policy.check('zone_export', context, target) policy.check('zone_export', context, target)
export = self.central_api.get_zone_export(context, export_id) export = self.central_api.get_zone_export(context, export_id)

View File

@ -33,6 +33,7 @@ from oslo_config import cfg
from oslo_log import log as logging from oslo_log import log as logging
import oslo_messaging as messaging import oslo_messaging as messaging
from designate.common import constants
from designate import context as dcontext from designate import context as dcontext
from designate import coordination from designate import coordination
from designate import dnsutils from designate import dnsutils
@ -483,6 +484,12 @@ class Service(service.RPCService):
raise exceptions.InvalidTTL('TTL is below the minimum: %s' raise exceptions.InvalidTTL('TTL is below the minimum: %s'
% min_ttl) % min_ttl)
def _is_valid_project_id(self, project_id):
if project_id is None:
raise exceptions.MissingProjectID(
"A project ID must be specified when not using a project "
"scoped token.")
def _increment_zone_serial(self, context, zone, set_delayed_notify=False): def _increment_zone_serial(self, context, zone, set_delayed_notify=False):
"""Update the zone serial and the SOA record """Update the zone serial and the SOA record
Optionally set delayed_notify to have PM issue delayed notify Optionally set delayed_notify to have PM issue delayed notify
@ -658,16 +665,29 @@ class Service(service.RPCService):
# Quota Methods # Quota Methods
@rpc.expected_exceptions() @rpc.expected_exceptions()
def get_quotas(self, context, tenant_id): def get_quotas(self, context, tenant_id):
if policy.enforce_new_defaults():
target = {constants.RBAC_PROJECT_ID: tenant_id,
'all_tenants': context.all_tenants}
else:
target = {'tenant_id': tenant_id} target = {'tenant_id': tenant_id}
policy.check('get_quotas', context, target) policy.check('get_quotas', context, target)
if tenant_id != context.project_id and not context.all_tenants: # TODO(johnsom) Deprecated since Wallaby, remove with legacy default
# policies. System scoped admin doesn't have a project_id
if (tenant_id != context.project_id and not context.all_tenants and not
policy.enforce_new_defaults()):
raise exceptions.Forbidden() raise exceptions.Forbidden()
return self.quota.get_quotas(context, tenant_id) return self.quota.get_quotas(context, tenant_id)
@rpc.expected_exceptions() @rpc.expected_exceptions()
def get_quota(self, context, tenant_id, resource): def get_quota(self, context, tenant_id, resource):
if policy.enforce_new_defaults():
target = {
constants.RBAC_PROJECT_ID: tenant_id,
'resource': resource
}
else:
target = {'tenant_id': tenant_id, 'resource': resource} target = {'tenant_id': tenant_id, 'resource': resource}
policy.check('get_quota', context, target) policy.check('get_quota', context, target)
@ -676,6 +696,13 @@ class Service(service.RPCService):
@rpc.expected_exceptions() @rpc.expected_exceptions()
@transaction @transaction
def set_quota(self, context, tenant_id, resource, hard_limit): def set_quota(self, context, tenant_id, resource, hard_limit):
if policy.enforce_new_defaults():
target = {
constants.RBAC_PROJECT_ID: tenant_id,
'resource': resource,
'hard_limit': hard_limit,
}
else:
target = { target = {
'tenant_id': tenant_id, 'tenant_id': tenant_id,
'resource': resource, 'resource': resource,
@ -683,13 +710,19 @@ class Service(service.RPCService):
} }
policy.check('set_quota', context, target) policy.check('set_quota', context, target)
if tenant_id != context.project_id and not context.all_tenants: # TODO(johnsom) Deprecated since Wallaby, remove with legacy default
# policies. System scoped admin doesn't have a project_id
if (tenant_id != context.project_id and not context.all_tenants and not
policy.enforce_new_defaults()):
raise exceptions.Forbidden() raise exceptions.Forbidden()
return self.quota.set_quota(context, tenant_id, resource, hard_limit) return self.quota.set_quota(context, tenant_id, resource, hard_limit)
@transaction @transaction
def reset_quotas(self, context, tenant_id): def reset_quotas(self, context, tenant_id):
if policy.enforce_new_defaults():
target = {constants.RBAC_PROJECT_ID: tenant_id}
else:
target = {'tenant_id': tenant_id} target = {'tenant_id': tenant_id}
policy.check('reset_quotas', context, target) policy.check('reset_quotas', context, target)
@ -806,9 +839,10 @@ class Service(service.RPCService):
@rpc.expected_exceptions() @rpc.expected_exceptions()
def get_tenant(self, context, tenant_id): def get_tenant(self, context, tenant_id):
target = { if policy.enforce_new_defaults():
'tenant_id': tenant_id target = {constants.RBAC_PROJECT_ID: tenant_id}
} else:
target = {'tenant_id': tenant_id}
policy.check('get_tenant', context, target) policy.check('get_tenant', context, target)
@ -855,6 +889,12 @@ class Service(service.RPCService):
# Default to creating in the current users tenant # Default to creating in the current users tenant
zone.tenant_id = zone.tenant_id or context.project_id zone.tenant_id = zone.tenant_id or context.project_id
if policy.enforce_new_defaults():
target = {
constants.RBAC_PROJECT_ID: zone.tenant_id,
'zone_name': zone.name
}
else:
target = { target = {
'tenant_id': zone.tenant_id, 'tenant_id': zone.tenant_id,
'zone_name': zone.name 'zone_name': zone.name
@ -862,6 +902,8 @@ class Service(service.RPCService):
policy.check('create_zone', context, target) policy.check('create_zone', context, target)
self._is_valid_project_id(zone.tenant_id)
# Ensure the tenant has enough quota to continue # Ensure the tenant has enough quota to continue
self._enforce_zone_quota(context, zone.tenant_id) self._enforce_zone_quota(context, zone.tenant_id)
@ -969,11 +1011,19 @@ class Service(service.RPCService):
""" """
zone = self.storage.get_zone(context, zone_id) zone = self.storage.get_zone(context, zone_id)
if policy.enforce_new_defaults():
target = {
'zone_id': zone_id,
'zone_name': zone.name,
constants.RBAC_PROJECT_ID: zone.tenant_id
}
else:
target = { target = {
'zone_id': zone_id, 'zone_id': zone_id,
'zone_name': zone.name, 'zone_name': zone.name,
'tenant_id': zone.tenant_id 'tenant_id': zone.tenant_id
} }
policy.check('get_zone', context, target) policy.check('get_zone', context, target)
return zone return zone
@ -986,6 +1036,14 @@ class Service(service.RPCService):
pool_id = cfg.CONF['service:central'].default_pool_id pool_id = cfg.CONF['service:central'].default_pool_id
else: else:
zone = self.storage.get_zone(context, zone_id) zone = self.storage.get_zone(context, zone_id)
if policy.enforce_new_defaults():
target = {
'zone_id': zone_id,
'zone_name': zone.name,
constants.RBAC_PROJECT_ID: zone.tenant_id
}
else:
target = { target = {
'zone_id': zone_id, 'zone_id': zone_id,
'zone_name': zone.name, 'zone_name': zone.name,
@ -1008,7 +1066,11 @@ class Service(service.RPCService):
sort_key=None, sort_dir=None): sort_key=None, sort_dir=None):
"""List existing zones including the ones flagged for deletion. """List existing zones including the ones flagged for deletion.
""" """
if policy.enforce_new_defaults():
target = {constants.RBAC_PROJECT_ID: context.project_id}
else:
target = {'tenant_id': context.project_id} target = {'tenant_id': context.project_id}
policy.check('find_zones', context, target) policy.check('find_zones', context, target)
return self.storage.find_zones(context, criterion, marker, limit, return self.storage.find_zones(context, criterion, marker, limit,
@ -1016,7 +1078,11 @@ class Service(service.RPCService):
@rpc.expected_exceptions() @rpc.expected_exceptions()
def find_zone(self, context, criterion=None): def find_zone(self, context, criterion=None):
if policy.enforce_new_defaults():
target = {constants.RBAC_PROJECT_ID: context.project_id}
else:
target = {'tenant_id': context.project_id} target = {'tenant_id': context.project_id}
policy.check('find_zone', context, target) policy.check('find_zone', context, target)
return self.storage.find_zone(context, criterion) return self.storage.find_zone(context, criterion)
@ -1030,6 +1096,14 @@ class Service(service.RPCService):
:returns: updated zone :returns: updated zone
""" """
if policy.enforce_new_defaults():
target = {
'zone_id': zone.obj_get_original_value('id'),
'zone_name': zone.obj_get_original_value('name'),
constants.RBAC_PROJECT_ID: (
zone.obj_get_original_value('tenant_id')),
}
else:
target = { target = {
'zone_id': zone.obj_get_original_value('id'), 'zone_id': zone.obj_get_original_value('id'),
'zone_name': zone.obj_get_original_value('name'), 'zone_name': zone.obj_get_original_value('name'),
@ -1100,6 +1174,13 @@ class Service(service.RPCService):
""" """
zone = self.storage.get_zone(context, zone_id) zone = self.storage.get_zone(context, zone_id)
if policy.enforce_new_defaults():
target = {
'zone_id': zone_id,
'zone_name': zone.name,
constants.RBAC_PROJECT_ID: zone.tenant_id
}
else:
target = { target = {
'zone_id': zone_id, 'zone_id': zone_id,
'zone_name': zone.name, 'zone_name': zone.name,
@ -1159,6 +1240,13 @@ class Service(service.RPCService):
def xfr_zone(self, context, zone_id): def xfr_zone(self, context, zone_id):
zone = self.storage.get_zone(context, zone_id) zone = self.storage.get_zone(context, zone_id)
if policy.enforce_new_defaults():
target = {
'zone_id': zone_id,
'zone_name': zone.name,
constants.RBAC_PROJECT_ID: zone.tenant_id
}
else:
target = { target = {
'zone_id': zone_id, 'zone_id': zone_id,
'zone_name': zone.name, 'zone_name': zone.name,
@ -1189,6 +1277,11 @@ class Service(service.RPCService):
if criterion is None: if criterion is None:
criterion = {} criterion = {}
if policy.enforce_new_defaults():
target = {
constants.RBAC_PROJECT_ID: criterion.get('tenant_id', None)
}
else:
target = { target = {
'tenant_id': criterion.get('tenant_id', None) 'tenant_id': criterion.get('tenant_id', None)
} }
@ -1233,6 +1326,13 @@ class Service(service.RPCService):
def touch_zone(self, context, zone_id): def touch_zone(self, context, zone_id):
zone = self.storage.get_zone(context, zone_id) zone = self.storage.get_zone(context, zone_id)
if policy.enforce_new_defaults():
target = {
'zone_id': zone_id,
'zone_name': zone.name,
constants.RBAC_PROJECT_ID: zone.tenant_id
}
else:
target = { target = {
'zone_id': zone_id, 'zone_id': zone_id,
'zone_name': zone.name, 'zone_name': zone.name,
@ -1266,6 +1366,15 @@ class Service(service.RPCService):
if zone.action == 'DELETE': if zone.action == 'DELETE':
raise exceptions.BadRequest('Can not update a deleting zone') raise exceptions.BadRequest('Can not update a deleting zone')
if policy.enforce_new_defaults():
target = {
'zone_id': zone_id,
'zone_name': zone.name,
'zone_type': zone.type,
'recordset_name': recordset.name,
constants.RBAC_PROJECT_ID: zone.tenant_id,
}
else:
target = { target = {
'zone_id': zone_id, 'zone_id': zone_id,
'zone_name': zone.name, 'zone_name': zone.name,
@ -1357,6 +1466,14 @@ class Service(service.RPCService):
else: else:
zone = self.storage.get_zone(context, recordset.zone_id) zone = self.storage.get_zone(context, recordset.zone_id)
if policy.enforce_new_defaults():
target = {
'zone_id': zone.id,
'zone_name': zone.name,
'recordset_id': recordset.id,
constants.RBAC_PROJECT_ID: zone.tenant_id,
}
else:
target = { target = {
'zone_id': zone.id, 'zone_id': zone.id,
'zone_name': zone.name, 'zone_name': zone.name,
@ -1375,7 +1492,11 @@ class Service(service.RPCService):
@rpc.expected_exceptions() @rpc.expected_exceptions()
def find_recordsets(self, context, criterion=None, marker=None, limit=None, def find_recordsets(self, context, criterion=None, marker=None, limit=None,
sort_key=None, sort_dir=None, force_index=False): sort_key=None, sort_dir=None, force_index=False):
if policy.enforce_new_defaults():
target = {constants.RBAC_PROJECT_ID: context.project_id}
else:
target = {'tenant_id': context.project_id} target = {'tenant_id': context.project_id}
policy.check('find_recordsets', context, target) policy.check('find_recordsets', context, target)
recordsets = self.storage.find_recordsets(context, criterion, marker, recordsets = self.storage.find_recordsets(context, criterion, marker,
@ -1386,6 +1507,9 @@ class Service(service.RPCService):
@rpc.expected_exceptions() @rpc.expected_exceptions()
def find_recordset(self, context, criterion=None): def find_recordset(self, context, criterion=None):
if policy.enforce_new_defaults():
target = {constants.RBAC_PROJECT_ID: context.project_id}
else:
target = {'tenant_id': context.project_id} target = {'tenant_id': context.project_id}
policy.check('find_recordset', context, target) policy.check('find_recordset', context, target)
@ -1430,6 +1554,15 @@ class Service(service.RPCService):
if zone.action == 'DELETE': if zone.action == 'DELETE':
raise exceptions.BadRequest('Can not update a deleting zone') raise exceptions.BadRequest('Can not update a deleting zone')
if policy.enforce_new_defaults():
target = {
'zone_id': recordset.obj_get_original_value('zone_id'),
'zone_type': zone.type,
'recordset_id': recordset.obj_get_original_value('id'),
'zone_name': zone.name,
constants.RBAC_PROJECT_ID: zone.tenant_id
}
else:
target = { target = {
'zone_id': recordset.obj_get_original_value('zone_id'), 'zone_id': recordset.obj_get_original_value('zone_id'),
'zone_type': zone.type, 'zone_type': zone.type,
@ -1494,6 +1627,15 @@ class Service(service.RPCService):
if zone.action == 'DELETE': if zone.action == 'DELETE':
raise exceptions.BadRequest('Can not update a deleting zone') raise exceptions.BadRequest('Can not update a deleting zone')
if policy.enforce_new_defaults():
target = {
'zone_id': zone_id,
'zone_name': zone.name,
'zone_type': zone.type,
'recordset_id': recordset.id,
constants.RBAC_PROJECT_ID: zone.tenant_id
}
else:
target = { target = {
'zone_id': zone_id, 'zone_id': zone_id,
'zone_name': zone.name, 'zone_name': zone.name,
@ -1543,9 +1685,12 @@ class Service(service.RPCService):
if criterion is None: if criterion is None:
criterion = {} criterion = {}
if policy.enforce_new_defaults():
target = { target = {
'tenant_id': criterion.get('tenant_id', None) constants.RBAC_PROJECT_ID: criterion.get('tenant_id', None)
} }
else:
target = {'tenant_id': criterion.get('tenant_id', None)}
policy.check('count_recordsets', context, target) policy.check('count_recordsets', context, target)
@ -1565,6 +1710,16 @@ class Service(service.RPCService):
recordset = self.storage.get_recordset(context, recordset_id) recordset = self.storage.get_recordset(context, recordset_id)
if policy.enforce_new_defaults():
target = {
'zone_id': zone_id,
'zone_name': zone.name,
'zone_type': zone.type,
'recordset_id': recordset_id,
'recordset_name': recordset.name,
constants.RBAC_PROJECT_ID: zone.tenant_id
}
else:
target = { target = {
'zone_id': zone_id, 'zone_id': zone_id,
'zone_name': zone.name, 'zone_name': zone.name,
@ -1619,6 +1774,16 @@ class Service(service.RPCService):
if recordset.id != record.recordset_id: if recordset.id != record.recordset_id:
raise exceptions.RecordNotFound() raise exceptions.RecordNotFound()
if policy.enforce_new_defaults():
target = {
'zone_id': zone_id,
'zone_name': zone.name,
'recordset_id': recordset_id,
'recordset_name': recordset.name,
'record_id': record.id,
constants.RBAC_PROJECT_ID: zone.tenant_id
}
else:
target = { target = {
'zone_id': zone_id, 'zone_id': zone_id,
'zone_name': zone.name, 'zone_name': zone.name,
@ -1635,6 +1800,10 @@ class Service(service.RPCService):
@rpc.expected_exceptions() @rpc.expected_exceptions()
def find_records(self, context, criterion=None, marker=None, limit=None, def find_records(self, context, criterion=None, marker=None, limit=None,
sort_key=None, sort_dir=None): sort_key=None, sort_dir=None):
if policy.enforce_new_defaults():
target = {constants.RBAC_PROJECT_ID: context.project_id}
else:
target = {'tenant_id': context.project_id} target = {'tenant_id': context.project_id}
policy.check('find_records', context, target) policy.check('find_records', context, target)
@ -1643,6 +1812,10 @@ class Service(service.RPCService):
@rpc.expected_exceptions() @rpc.expected_exceptions()
def find_record(self, context, criterion=None): def find_record(self, context, criterion=None):
if policy.enforce_new_defaults():
target = {constants.RBAC_PROJECT_ID: context.project_id}
else:
target = {'tenant_id': context.project_id} target = {'tenant_id': context.project_id}
policy.check('find_record', context, target) policy.check('find_record', context, target)
@ -1677,6 +1850,17 @@ class Service(service.RPCService):
raise exceptions.BadRequest('Moving a recordset between ' raise exceptions.BadRequest('Moving a recordset between '
'recordsets is not allowed') 'recordsets is not allowed')
if policy.enforce_new_defaults():
target = {
'zone_id': record.obj_get_original_value('zone_id'),
'zone_name': zone.name,
'zone_type': zone.type,
'recordset_id': record.obj_get_original_value('recordset_id'),
'recordset_name': recordset.name,
'record_id': record.obj_get_original_value('id'),
constants.RBAC_PROJECT_ID: zone.tenant_id
}
else:
target = { target = {
'zone_id': record.obj_get_original_value('zone_id'), 'zone_id': record.obj_get_original_value('zone_id'),
'zone_name': zone.name, 'zone_name': zone.name,
@ -1739,6 +1923,17 @@ class Service(service.RPCService):
if recordset.id != record.recordset_id: if recordset.id != record.recordset_id:
raise exceptions.RecordNotFound() raise exceptions.RecordNotFound()
if policy.enforce_new_defaults():
target = {
'zone_id': zone_id,
'zone_name': zone.name,
'zone_type': zone.type,
'recordset_id': recordset_id,
'recordset_name': recordset.name,
'record_id': record.id,
constants.RBAC_PROJECT_ID: zone.tenant_id
}
else:
target = { target = {
'zone_id': zone_id, 'zone_id': zone_id,
'zone_name': zone.name, 'zone_name': zone.name,
@ -1783,9 +1978,12 @@ class Service(service.RPCService):
if criterion is None: if criterion is None:
criterion = {} criterion = {}
if policy.enforce_new_defaults():
target = { target = {
'tenant_id': criterion.get('tenant_id', None) constants.RBAC_PROJECT_ID: criterion.get('tenant_id', None)
} }
else:
target = {'tenant_id': criterion.get('tenant_id', None)}
policy.check('count_records', context, target) policy.check('count_records', context, target)
return self.storage.count_records(context, criterion) return self.storage.count_records(context, criterion)
@ -1812,6 +2010,13 @@ class Service(service.RPCService):
def sync_zone(self, context, zone_id): def sync_zone(self, context, zone_id):
zone = self.storage.get_zone(context, zone_id) zone = self.storage.get_zone(context, zone_id)
if policy.enforce_new_defaults():
target = {
'zone_id': zone_id,
'zone_name': zone.name,
constants.RBAC_PROJECT_ID: zone.tenant_id
}
else:
target = { target = {
'zone_id': zone_id, 'zone_id': zone_id,
'zone_name': zone.name, 'zone_name': zone.name,
@ -1828,6 +2033,16 @@ class Service(service.RPCService):
zone = self.storage.get_zone(context, zone_id) zone = self.storage.get_zone(context, zone_id)
recordset = self.storage.get_recordset(context, recordset_id) recordset = self.storage.get_recordset(context, recordset_id)
if policy.enforce_new_defaults():
target = {
'zone_id': zone_id,
'zone_name': zone.name,
'recordset_id': recordset_id,
'recordset_name': recordset.name,
'record_id': record_id,
constants.RBAC_PROJECT_ID: zone.tenant_id
}
else:
target = { target = {
'zone_id': zone_id, 'zone_id': zone_id,
'zone_name': zone.name, 'zone_name': zone.name,
@ -2255,6 +2470,8 @@ class Service(service.RPCService):
policy.check('create_pool', context) policy.check('create_pool', context)
self._is_valid_project_id(pool.tenant_id)
created_pool = self.storage.create_pool(context, pool) created_pool = self.storage.create_pool(context, pool)
return created_pool return created_pool
@ -2506,9 +2723,11 @@ class Service(service.RPCService):
if zone.action == 'DELETE': if zone.action == 'DELETE':
raise exceptions.BadRequest('Can not transfer a deleting zone') raise exceptions.BadRequest('Can not transfer a deleting zone')
target = { if policy.enforce_new_defaults():
'tenant_id': zone.tenant_id, target = {constants.RBAC_PROJECT_ID: zone.tenant_id}
} else:
target = {'tenant_id': zone.tenant_id}
policy.check('create_zone_transfer_request', context, target) policy.check('create_zone_transfer_request', context, target)
zone_transfer_request.key = self._transfer_key_generator() zone_transfer_request.key = self._transfer_key_generator()
@ -2516,6 +2735,8 @@ class Service(service.RPCService):
if zone_transfer_request.tenant_id is None: if zone_transfer_request.tenant_id is None:
zone_transfer_request.tenant_id = context.project_id zone_transfer_request.tenant_id = context.project_id
self._is_valid_project_id(zone_transfer_request.tenant_id)
created_zone_transfer_request = \ created_zone_transfer_request = \
self.storage.create_zone_transfer_request( self.storage.create_zone_transfer_request(
context, zone_transfer_request) context, zone_transfer_request)
@ -2532,10 +2753,18 @@ class Service(service.RPCService):
elevated_context, zone_transfer_request_id) elevated_context, zone_transfer_request_id)
LOG.info('Target Tenant ID found - using scoped policy') LOG.info('Target Tenant ID found - using scoped policy')
if policy.enforce_new_defaults():
target = {
constants.RBAC_TARGET_PROJECT_ID: (zone_transfer_request.
target_tenant_id),
constants.RBAC_PROJECT_ID: zone_transfer_request.tenant_id,
}
else:
target = { target = {
'target_tenant_id': zone_transfer_request.target_tenant_id, 'target_tenant_id': zone_transfer_request.target_tenant_id,
'tenant_id': zone_transfer_request.tenant_id, 'tenant_id': zone_transfer_request.tenant_id,
} }
policy.check('get_zone_transfer_request', context, target) policy.check('get_zone_transfer_request', context, target)
return zone_transfer_request return zone_transfer_request
@ -2555,9 +2784,15 @@ class Service(service.RPCService):
@rpc.expected_exceptions() @rpc.expected_exceptions()
def find_zone_transfer_request(self, context, criterion): def find_zone_transfer_request(self, context, criterion):
if policy.enforce_new_defaults():
target = {
constants.RBAC_PROJECT_ID: context.project_id,
}
else:
target = { target = {
'tenant_id': context.project_id, 'tenant_id': context.project_id,
} }
policy.check('find_zone_transfer_request', context, target) policy.check('find_zone_transfer_request', context, target)
return self.storage.find_zone_transfer_requests(context, criterion) return self.storage.find_zone_transfer_requests(context, criterion)
@ -2569,6 +2804,11 @@ class Service(service.RPCService):
if 'zone_id' in zone_transfer_request.obj_what_changed(): if 'zone_id' in zone_transfer_request.obj_what_changed():
raise exceptions.InvalidOperation('Zone cannot be changed') raise exceptions.InvalidOperation('Zone cannot be changed')
if policy.enforce_new_defaults():
target = {
constants.RBAC_PROJECT_ID: zone_transfer_request.tenant_id,
}
else:
target = { target = {
'tenant_id': zone_transfer_request.tenant_id, 'tenant_id': zone_transfer_request.tenant_id,
} }
@ -2585,9 +2825,14 @@ class Service(service.RPCService):
# Get zone transfer request # Get zone transfer request
zone_transfer_request = self.storage.get_zone_transfer_request( zone_transfer_request = self.storage.get_zone_transfer_request(
context, zone_transfer_request_id) context, zone_transfer_request_id)
if policy.enforce_new_defaults():
target = { target = {
'tenant_id': zone_transfer_request.tenant_id, constants.RBAC_PROJECT_ID: zone_transfer_request.tenant_id
} }
else:
target = {'tenant_id': zone_transfer_request.tenant_id}
policy.check('delete_zone_transfer_request', context, target) policy.check('delete_zone_transfer_request', context, target)
return self.storage.delete_zone_transfer_request( return self.storage.delete_zone_transfer_request(
context, context,
@ -2614,14 +2859,23 @@ class Service(service.RPCService):
raise exceptions.IncorrectZoneTransferKey( raise exceptions.IncorrectZoneTransferKey(
'Key does not match stored key for request') 'Key does not match stored key for request')
if policy.enforce_new_defaults():
target = {
constants.RBAC_TARGET_PROJECT_ID: (zone_transfer_request.
target_tenant_id)
}
else:
target = { target = {
'target_tenant_id': zone_transfer_request.target_tenant_id 'target_tenant_id': zone_transfer_request.target_tenant_id
} }
policy.check('create_zone_transfer_accept', context, target) policy.check('create_zone_transfer_accept', context, target)
if zone_transfer_accept.tenant_id is None: if zone_transfer_accept.tenant_id is None:
zone_transfer_accept.tenant_id = context.project_id zone_transfer_accept.tenant_id = context.project_id
self._is_valid_project_id(zone_transfer_accept.tenant_id)
created_zone_transfer_accept = \ created_zone_transfer_accept = \
self.storage.create_zone_transfer_accept( self.storage.create_zone_transfer_accept(
context, zone_transfer_accept) context, zone_transfer_accept)
@ -2664,9 +2918,15 @@ class Service(service.RPCService):
zone_transfer_accept = self.storage.get_zone_transfer_accept( zone_transfer_accept = self.storage.get_zone_transfer_accept(
context, zone_transfer_accept_id) context, zone_transfer_accept_id)
if policy.enforce_new_defaults():
target = {
constants.RBAC_PROJECT_ID: zone_transfer_accept.tenant_id
}
else:
target = { target = {
'tenant_id': zone_transfer_accept.tenant_id 'tenant_id': zone_transfer_accept.tenant_id
} }
policy.check('get_zone_transfer_accept', context, target) policy.check('get_zone_transfer_accept', context, target)
return zone_transfer_accept return zone_transfer_accept
@ -2688,6 +2948,11 @@ class Service(service.RPCService):
@notification('dns.zone_transfer_accept.update') @notification('dns.zone_transfer_accept.update')
@transaction @transaction
def update_zone_transfer_accept(self, context, zone_transfer_accept): def update_zone_transfer_accept(self, context, zone_transfer_accept):
if policy.enforce_new_defaults():
target = {
constants.RBAC_PROJECT_ID: zone_transfer_accept.tenant_id
}
else:
target = { target = {
'tenant_id': zone_transfer_accept.tenant_id 'tenant_id': zone_transfer_accept.tenant_id
} }
@ -2705,9 +2970,15 @@ class Service(service.RPCService):
zt_accept = self.storage.get_zone_transfer_accept( zt_accept = self.storage.get_zone_transfer_accept(
context, zone_transfer_accept_id) context, zone_transfer_accept_id)
if policy.enforce_new_defaults():
target = {
constants.RBAC_PROJECT_ID: zt_accept.tenant_id
}
else:
target = { target = {
'tenant_id': zt_accept.tenant_id 'tenant_id': zt_accept.tenant_id
} }
policy.check('delete_zone_transfer_accept', context, target) policy.check('delete_zone_transfer_accept', context, target)
return self.storage.delete_zone_transfer_accept( return self.storage.delete_zone_transfer_accept(
context, context,
@ -2717,9 +2988,16 @@ class Service(service.RPCService):
@rpc.expected_exceptions() @rpc.expected_exceptions()
@notification('dns.zone_import.create') @notification('dns.zone_import.create')
def create_zone_import(self, context, request_body): def create_zone_import(self, context, request_body):
if policy.enforce_new_defaults():
target = {constants.RBAC_PROJECT_ID: context.project_id}
else:
target = {'tenant_id': context.project_id} target = {'tenant_id': context.project_id}
policy.check('create_zone_import', context, target) policy.check('create_zone_import', context, target)
self._is_valid_project_id(context.project_id)
values = { values = {
'status': 'PENDING', 'status': 'PENDING',
'message': None, 'message': None,
@ -2811,7 +3089,12 @@ class Service(service.RPCService):
@rpc.expected_exceptions() @rpc.expected_exceptions()
def find_zone_imports(self, context, criterion=None, marker=None, def find_zone_imports(self, context, criterion=None, marker=None,
limit=None, sort_key=None, sort_dir=None): limit=None, sort_key=None, sort_dir=None):
if policy.enforce_new_defaults():
target = {constants.RBAC_PROJECT_ID: context.project_id}
else:
target = {'tenant_id': context.project_id} target = {'tenant_id': context.project_id}
policy.check('find_zone_imports', context, target) policy.check('find_zone_imports', context, target)
if not criterion: if not criterion:
@ -2826,16 +3109,22 @@ class Service(service.RPCService):
@rpc.expected_exceptions() @rpc.expected_exceptions()
def get_zone_import(self, context, zone_import_id): def get_zone_import(self, context, zone_import_id):
if policy.enforce_new_defaults():
target = {constants.RBAC_PROJECT_ID: context.project_id}
else:
target = {'tenant_id': context.project_id} target = {'tenant_id': context.project_id}
policy.check('get_zone_import', context, target) policy.check('get_zone_import', context, target)
return self.storage.get_zone_import(context, zone_import_id) return self.storage.get_zone_import(context, zone_import_id)
@rpc.expected_exceptions() @rpc.expected_exceptions()
@notification('dns.zone_import.update') @notification('dns.zone_import.update')
def update_zone_import(self, context, zone_import): def update_zone_import(self, context, zone_import):
target = { if policy.enforce_new_defaults():
'tenant_id': zone_import.tenant_id, target = {constants.RBAC_PROJECT_ID: zone_import.tenant_id}
} else:
target = {'tenant_id': zone_import.tenant_id}
policy.check('update_zone_import', context, target) policy.check('update_zone_import', context, target)
return self.storage.update_zone_import(context, zone_import) return self.storage.update_zone_import(context, zone_import)
@ -2844,10 +3133,18 @@ class Service(service.RPCService):
@notification('dns.zone_import.delete') @notification('dns.zone_import.delete')
@transaction @transaction
def delete_zone_import(self, context, zone_import_id): def delete_zone_import(self, context, zone_import_id):
if policy.enforce_new_defaults():
target = {
'zone_import_id': zone_import_id,
constants.RBAC_PROJECT_ID: context.project_id
}
else:
target = { target = {
'zone_import_id': zone_import_id, 'zone_import_id': zone_import_id,
'tenant_id': context.project_id 'tenant_id': context.project_id
} }
policy.check('delete_zone_import', context, target) policy.check('delete_zone_import', context, target)
zone_import = self.storage.delete_zone_import(context, zone_import_id) zone_import = self.storage.delete_zone_import(context, zone_import_id)
@ -2861,9 +3158,15 @@ class Service(service.RPCService):
# Try getting the zone to ensure it exists # Try getting the zone to ensure it exists
zone = self.storage.get_zone(context, zone_id) zone = self.storage.get_zone(context, zone_id)
if policy.enforce_new_defaults():
target = {constants.RBAC_PROJECT_ID: context.project_id}
else:
target = {'tenant_id': context.project_id} target = {'tenant_id': context.project_id}
policy.check('create_zone_export', context, target) policy.check('create_zone_export', context, target)
self._is_valid_project_id(context.project_id)
values = { values = {
'status': 'PENDING', 'status': 'PENDING',
'message': None, 'message': None,
@ -2884,6 +3187,10 @@ class Service(service.RPCService):
@rpc.expected_exceptions() @rpc.expected_exceptions()
def find_zone_exports(self, context, criterion=None, marker=None, def find_zone_exports(self, context, criterion=None, marker=None,
limit=None, sort_key=None, sort_dir=None): limit=None, sort_key=None, sort_dir=None):
if policy.enforce_new_defaults():
target = {constants.RBAC_PROJECT_ID: context.project_id}
else:
target = {'tenant_id': context.project_id} target = {'tenant_id': context.project_id}
policy.check('find_zone_exports', context, target) policy.check('find_zone_exports', context, target)
@ -2899,7 +3206,12 @@ class Service(service.RPCService):
@rpc.expected_exceptions() @rpc.expected_exceptions()
def get_zone_export(self, context, zone_export_id): def get_zone_export(self, context, zone_export_id):
if policy.enforce_new_defaults():
target = {constants.RBAC_PROJECT_ID: context.project_id}
else:
target = {'tenant_id': context.project_id} target = {'tenant_id': context.project_id}
policy.check('get_zone_export', context, target) policy.check('get_zone_export', context, target)
return self.storage.get_zone_export(context, zone_export_id) return self.storage.get_zone_export(context, zone_export_id)
@ -2907,9 +3219,12 @@ class Service(service.RPCService):
@rpc.expected_exceptions() @rpc.expected_exceptions()
@notification('dns.zone_export.update') @notification('dns.zone_export.update')
def update_zone_export(self, context, zone_export): def update_zone_export(self, context, zone_export):
target = {
'tenant_id': zone_export.tenant_id, if policy.enforce_new_defaults():
} target = {constants.RBAC_PROJECT_ID: zone_export.tenant_id}
else:
target = {'tenant_id': zone_export.tenant_id}
policy.check('update_zone_export', context, target) policy.check('update_zone_export', context, target)
return self.storage.update_zone_export(context, zone_export) return self.storage.update_zone_export(context, zone_export)
@ -2918,10 +3233,18 @@ class Service(service.RPCService):
@notification('dns.zone_export.delete') @notification('dns.zone_export.delete')
@transaction @transaction
def delete_zone_export(self, context, zone_export_id): def delete_zone_export(self, context, zone_export_id):
if policy.enforce_new_defaults():
target = {
'zone_export_id': zone_export_id,
constants.RBAC_PROJECT_ID: context.project_id
}
else:
target = { target = {
'zone_export_id': zone_export_id, 'zone_export_id': zone_export_id,
'tenant_id': context.project_id 'tenant_id': context.project_id
} }
policy.check('delete_zone_export', context, target) policy.check('delete_zone_export', context, target)
zone_export = self.storage.delete_zone_export(context, zone_export_id) zone_export = self.storage.delete_zone_export(context, zone_export_id)

View File

@ -0,0 +1,17 @@
# Copyright 2021 Red Hat
#
# Licensed under the Apache License, Version 2.0 (the "License"); you may
# not use this file except in compliance with the License. You may obtain
# a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
# License for the specific language governing permissions and limitations
# under the License.
# RBAC related constants
RBAC_PROJECT_ID = 'project_id'
RBAC_TARGET_PROJECT_ID = 'target_project_id'

View File

@ -12,17 +12,14 @@
# License for the specific language governing permissions and limitations # License for the specific language governing permissions and limitations
# under the License. # under the License.
from oslo_log import versionutils
from oslo_policy import policy from oslo_policy import policy
RULE_ADMIN_OR_OWNER = 'rule:admin_or_owner' DEPRECATED_REASON = """
RULE_ADMIN = 'rule:admin' The designate API now supports system scope and default roles.
RULE_ZONE_PRIMARY_OR_ADMIN = \ """
"('PRIMARY':%(zone_type)s and rule:admin_or_owner) "\
"OR ('SECONDARY':%(zone_type)s AND is_admin:True)"
RULE_ZONE_TRANSFER = "rule:admin_or_owner OR tenant:%(target_tenant_id)s " \
"OR None:%(target_tenant_id)s"
RULE_ANY = "@" RULE_ANY = "@"
# Generic policy check string for system administrators. These are the people # Generic policy check string for system administrators. These are the people
@ -59,37 +56,56 @@ SYSTEM_OR_PROJECT_READER = (
'(' + SYSTEM_READER + ') or (' + PROJECT_READER + ')' '(' + SYSTEM_READER + ') or (' + PROJECT_READER + ')'
) )
# Designate specific "secure RBAC" rules
ALL_TENANTS = 'True:%(all_tenants)s'
ALL_TENANTS_READER = ALL_TENANTS + ' and role:reader'
SYSTEM_OR_PROJECT_READER_OR_ALL_TENANTS_READER = (
'(' + SYSTEM_READER + ') or (' + PROJECT_READER + ') or (' +
ALL_TENANTS_READER + ')'
)
RULE_ZONE_TRANSFER = (
'(' + SYSTEM_ADMIN_OR_PROJECT_MEMBER + ') or '
'project_id:%(target_project_id)s or '
'None:%(target_project_id)s')
# Deprecated in Wallaby as part of the "secure RBAC" work.
# TODO(johnsom) remove when the deprecated RBAC rules are removed.
RULE_ADMIN = 'rule:admin'
RULE_ADMIN_OR_OWNER = 'rule:admin_or_owner'
LEGACY_RULE_ZONE_TRANSFER = "rule:admin_or_owner OR " \
"tenant:%(target_tenant_id)s " \
"OR None:%(target_tenant_id)s"
deprecated_default = policy.DeprecatedRule(
name="default",
check_str=RULE_ADMIN_OR_OWNER,
deprecated_reason=DEPRECATED_REASON,
deprecated_since=versionutils.deprecated.WALLABY
)
rules = [ rules = [
# TODO(johnsom) remove when the deprecated RBAC rules are removed.
policy.RuleDefault( policy.RuleDefault(
name="admin", name="admin",
check_str="role:admin or is_admin:True"), check_str="role:admin or is_admin:True"),
policy.RuleDefault( # TODO(johnsom) remove when the deprecated RBAC rules are removed.
name="primary_zone",
check_str="target.zone_type:SECONDARY"),
policy.RuleDefault( policy.RuleDefault(
name="owner", name="owner",
check_str="tenant:%(tenant_id)s"), check_str="tenant:%(tenant_id)s"),
# TODO(johnsom) remove when the deprecated RBAC rules are removed.
policy.RuleDefault( policy.RuleDefault(
name="admin_or_owner", name="admin_or_owner",
check_str="rule:admin or rule:owner"), check_str="rule:admin or rule:owner"),
# Default policy
policy.RuleDefault( policy.RuleDefault(
name="default", name="default",
check_str="rule:admin_or_owner"), check_str=SYSTEM_ADMIN_OR_PROJECT_MEMBER,
policy.RuleDefault( deprecated_rule=deprecated_default),
name="target",
check_str="tenant:%(target_tenant_id)s"),
policy.RuleDefault(
name="owner_or_target",
check_str="rule:target or rule:owner"),
policy.RuleDefault(
name="admin_or_owner_or_target",
check_str="rule:owner_or_target or rule:admin"),
policy.RuleDefault(
name="admin_or_target",
check_str="rule:admin or rule:target"),
policy.RuleDefault(
name="zone_primary_or_admin",
check_str=RULE_ZONE_PRIMARY_OR_ADMIN)
] ]

View File

@ -13,28 +13,62 @@
# under the License. # under the License.
from oslo_log import versionutils
from oslo_policy import policy from oslo_policy import policy
from designate.common.policies import base from designate.common.policies import base
deprecated_all_tenants = policy.DeprecatedRule(
name="all_tenants",
check_str=base.RULE_ADMIN,
deprecated_reason=base.DEPRECATED_REASON,
deprecated_since=versionutils.deprecated.WALLABY
)
deprecated_edit_managed_records = policy.DeprecatedRule(
name="edit_managed_records",
check_str=base.RULE_ADMIN,
deprecated_reason=base.DEPRECATED_REASON,
deprecated_since=versionutils.deprecated.WALLABY
)
deprecated_use_low_ttl = policy.DeprecatedRule(
name="use_low_ttl",
check_str=base.RULE_ADMIN,
deprecated_reason=base.DEPRECATED_REASON,
deprecated_since=versionutils.deprecated.WALLABY
)
deprecated_use_sudo = policy.DeprecatedRule(
name="use_sudo",
check_str=base.RULE_ADMIN,
deprecated_reason=base.DEPRECATED_REASON,
deprecated_since=versionutils.deprecated.WALLABY
)
rules = [ rules = [
policy.RuleDefault( policy.RuleDefault(
name="all_tenants", name="all_tenants",
check_str=base.RULE_ADMIN, check_str=base.SYSTEM_ADMIN,
description='Action on all tenants.'), scope_types=['system'],
description='Action on all tenants.',
deprecated_rule=deprecated_all_tenants),
policy.RuleDefault( policy.RuleDefault(
name="edit_managed_records", name="edit_managed_records",
check_str=base.RULE_ADMIN, check_str=base.SYSTEM_ADMIN,
description='Edit managed records.'), scope_types=['system'],
description='Edit managed records.',
deprecated_rule=deprecated_edit_managed_records),
policy.RuleDefault( policy.RuleDefault(
name="use_low_ttl", name="use_low_ttl",
check_str=base.RULE_ADMIN, check_str=base.SYSTEM_ADMIN,
description='Use low TTL.'), scope_types=['system'],
description='Use low TTL.',
deprecated_rule=deprecated_use_low_ttl),
policy.RuleDefault( policy.RuleDefault(
name="use_sudo", name="use_sudo",
check_str=base.RULE_ADMIN, check_str=base.SYSTEM_ADMIN,
description='Accept sudo from user to tenant.') scope_types=['system'],
description='Accept sudo from user to tenant.',
deprecated_rule=deprecated_use_sudo)
] ]

View File

@ -12,29 +12,62 @@
# License for the specific language governing permissions and limitations # License for the specific language governing permissions and limitations
# under the License. # under the License.
from oslo_log import versionutils
from oslo_policy import policy from oslo_policy import policy
from designate.common.policies import base from designate.common.policies import base
deprecated_diagnostics_ping = policy.DeprecatedRule(
name="diagnostics_ping",
check_str=base.RULE_ADMIN,
deprecated_reason=base.DEPRECATED_REASON,
deprecated_since=versionutils.deprecated.WALLABY
)
deprecated_diagnostics_sync_zones = policy.DeprecatedRule(
name="diagnostics_sync_zones",
check_str=base.RULE_ADMIN,
deprecated_reason=base.DEPRECATED_REASON,
deprecated_since=versionutils.deprecated.WALLABY
)
deprecated_diagnostics_sync_zone = policy.DeprecatedRule(
name="diagnostics_sync_zone",
check_str=base.RULE_ADMIN,
deprecated_reason=base.DEPRECATED_REASON,
deprecated_since=versionutils.deprecated.WALLABY
)
deprecated_diagnostics_sync_record = policy.DeprecatedRule(
name="diagnostics_sync_record",
check_str=base.RULE_ADMIN,
deprecated_reason=base.DEPRECATED_REASON,
deprecated_since=versionutils.deprecated.WALLABY
)
rules = [ rules = [
policy.RuleDefault( policy.RuleDefault(
name="diagnostics_ping", name="diagnostics_ping",
check_str=base.RULE_ADMIN, check_str=base.SYSTEM_ADMIN,
description='Diagnose ping.'), scope_types=['system'],
description='Diagnose ping.',
deprecated_rule=deprecated_diagnostics_ping),
policy.RuleDefault( policy.RuleDefault(
name="diagnostics_sync_zones", name="diagnostics_sync_zones",
check_str=base.RULE_ADMIN, check_str=base.SYSTEM_ADMIN,
description='Diagnose sync zones.'), scope_types=['system'],
description='Diagnose sync zones.',
deprecated_rule=deprecated_diagnostics_sync_zones),
policy.RuleDefault( policy.RuleDefault(
name="diagnostics_sync_zone", name="diagnostics_sync_zone",
check_str=base.RULE_ADMIN, check_str=base.SYSTEM_ADMIN,
description='Diagnose sync zone.'), scope_types=['system'],
description='Diagnose sync zone.',
deprecated_rule=deprecated_diagnostics_sync_zone),
policy.RuleDefault( policy.RuleDefault(
name="diagnostics_sync_record", name="diagnostics_sync_record",
check_str=base.RULE_ADMIN, check_str=base.SYSTEM_ADMIN,
description='Diagnose sync record.') scope_types=['system'],
description='Diagnose sync record.',
deprecated_rule=deprecated_diagnostics_sync_record)
] ]

View File

@ -50,7 +50,7 @@ deprecated_reset_quotas = policy.DeprecatedRule(
rules = [ rules = [
policy.DocumentedRuleDefault( policy.DocumentedRuleDefault(
name="get_quotas", name="get_quotas",
check_str=base.SYSTEM_OR_PROJECT_READER, check_str=base.SYSTEM_OR_PROJECT_READER_OR_ALL_TENANTS_READER,
scope_types=['system', 'project'], scope_types=['system', 'project'],
description="View Current Project's Quotas.", description="View Current Project's Quotas.",
operations=[ operations=[

View File

@ -22,9 +22,15 @@ DEPRECATED_REASON = """
The record set API now supports system scope and default roles. The record set API now supports system scope and default roles.
""" """
# Deprecated in Wallaby as part of the "secure RBAC" work.
# TODO(johnsom) remove when the deprecated RBAC rules are removed.
RULE_ZONE_PRIMARY_OR_ADMIN = (
"('PRIMARY':%(zone_type)s and rule:admin_or_owner) "
"OR ('SECONDARY':%(zone_type)s AND is_admin:True)")
deprecated_create_recordset = policy.DeprecatedRule( deprecated_create_recordset = policy.DeprecatedRule(
name="create_recordset", name="create_recordset",
check_str=base.RULE_ZONE_PRIMARY_OR_ADMIN, check_str=RULE_ZONE_PRIMARY_OR_ADMIN,
deprecated_reason=DEPRECATED_REASON, deprecated_reason=DEPRECATED_REASON,
deprecated_since=versionutils.deprecated.WALLABY deprecated_since=versionutils.deprecated.WALLABY
) )
@ -40,15 +46,27 @@ deprecated_get_recordset = policy.DeprecatedRule(
deprecated_reason=DEPRECATED_REASON, deprecated_reason=DEPRECATED_REASON,
deprecated_since=versionutils.deprecated.WALLABY deprecated_since=versionutils.deprecated.WALLABY
) )
deprecated_find_recordset = policy.DeprecatedRule(
name="find_recordset",
check_str=base.RULE_ADMIN_OR_OWNER,
deprecated_reason=DEPRECATED_REASON,
deprecated_since=versionutils.deprecated.WALLABY
)
deprecated_find_recordsets = policy.DeprecatedRule(
name="find_recordsets",
check_str=base.RULE_ADMIN_OR_OWNER,
deprecated_reason=DEPRECATED_REASON,
deprecated_since=versionutils.deprecated.WALLABY
)
deprecated_update_recordset = policy.DeprecatedRule( deprecated_update_recordset = policy.DeprecatedRule(
name="update_recordset", name="update_recordset",
check_str=base.RULE_ZONE_PRIMARY_OR_ADMIN, check_str=RULE_ZONE_PRIMARY_OR_ADMIN,
deprecated_reason=DEPRECATED_REASON, deprecated_reason=DEPRECATED_REASON,
deprecated_since=versionutils.deprecated.WALLABY deprecated_since=versionutils.deprecated.WALLABY
) )
deprecated_delete_recordset = policy.DeprecatedRule( deprecated_delete_recordset = policy.DeprecatedRule(
name="delete_recordset", name="delete_recordset",
check_str=base.RULE_ZONE_PRIMARY_OR_ADMIN, check_str=RULE_ZONE_PRIMARY_OR_ADMIN,
deprecated_reason=DEPRECATED_REASON, deprecated_reason=DEPRECATED_REASON,
deprecated_since=versionutils.deprecated.WALLABY deprecated_since=versionutils.deprecated.WALLABY
) )
@ -69,7 +87,7 @@ SYSTEM_ADMIN_AND_SECONDARY_ZONE = (
'(' + base.SYSTEM_ADMIN + ') and (\'SECONDARY\':%(zone_type)s)' '(' + base.SYSTEM_ADMIN + ') and (\'SECONDARY\':%(zone_type)s)'
) )
SYSTEM_ADMIN_OR_PROJECT_MEMBER = ''.join( SYSTEM_ADMIN_OR_PROJECT_MEMBER_ZONE_TYPE = ' or '.join(
[PROJECT_MEMBER_AND_PRIMARY_ZONE, [PROJECT_MEMBER_AND_PRIMARY_ZONE,
SYSTEM_ADMIN_AND_PRIMARY_ZONE, SYSTEM_ADMIN_AND_PRIMARY_ZONE,
SYSTEM_ADMIN_AND_SECONDARY_ZONE] SYSTEM_ADMIN_AND_SECONDARY_ZONE]
@ -79,16 +97,13 @@ SYSTEM_ADMIN_OR_PROJECT_MEMBER = ''.join(
rules = [ rules = [
policy.DocumentedRuleDefault( policy.DocumentedRuleDefault(
name="create_recordset", name="create_recordset",
check_str=SYSTEM_ADMIN_AND_SECONDARY_ZONE, check_str=SYSTEM_ADMIN_OR_PROJECT_MEMBER_ZONE_TYPE,
scope_types=['system', 'project'], scope_types=['system', 'project'],
description="Create Recordset", description="Create Recordset",
operations=[ operations=[
{ {
'path': '/v2/zones/{zone_id}/recordsets', 'path': '/v2/zones/{zone_id}/recordsets',
'method': 'POST' 'method': 'POST'
}, {
'path': '/v2/reverse/floatingips/{region}:{floatingip_id}',
'method': 'PATCH'
} }
], ],
deprecated_rule=deprecated_create_recordset deprecated_rule=deprecated_create_recordset
@ -108,35 +123,46 @@ rules = [
{ {
'path': '/v2/zones/{zone_id}/recordsets/{recordset_id}', 'path': '/v2/zones/{zone_id}/recordsets/{recordset_id}',
'method': 'GET' 'method': 'GET'
}, {
'path': '/v2/zones/{zone_id}/recordsets/{recordset_id}',
'method': 'DELETE'
}, {
'path': '/v2/zones/{zone_id}/recordsets/{recordset_id}',
'method': 'PUT'
} }
], ],
deprecated_rule=deprecated_get_recordset deprecated_rule=deprecated_get_recordset
), ),
policy.RuleDefault(
name="find_recordset",
check_str=base.SYSTEM_OR_PROJECT_READER,
scope_types=['system', 'project'],
description="List a Recordset in a Zone",
deprecated_rule=deprecated_find_recordset
),
policy.DocumentedRuleDefault(
name="find_recordsets",
check_str=base.SYSTEM_OR_PROJECT_READER,
scope_types=['system', 'project'],
description="List Recordsets in a Zone",
operations=[
{
'path': '/v2/zones/{zone_id}/recordsets',
'method': 'GET'
},
],
deprecated_rule=deprecated_find_recordsets
),
policy.DocumentedRuleDefault( policy.DocumentedRuleDefault(
name="update_recordset", name="update_recordset",
check_str=SYSTEM_ADMIN_AND_SECONDARY_ZONE, check_str=SYSTEM_ADMIN_OR_PROJECT_MEMBER_ZONE_TYPE,
scope_types=['system', 'project'], scope_types=['system', 'project'],
description="Update recordset", description="Update recordset",
operations=[ operations=[
{ {
'path': '/v2/zones/{zone_id}/recordsets/{recordset_id}', 'path': '/v2/zones/{zone_id}/recordsets/{recordset_id}',
'method': 'PUT' 'method': 'PUT'
}, {
'path': '/v2/reverse/floatingips/{region}:{floatingip_id}',
'method': 'PATCH'
} }
], ],
deprecated_rule=deprecated_update_recordset deprecated_rule=deprecated_update_recordset
), ),
policy.DocumentedRuleDefault( policy.DocumentedRuleDefault(
name="delete_recordset", name="delete_recordset",
check_str=SYSTEM_ADMIN_AND_SECONDARY_ZONE, check_str=SYSTEM_ADMIN_OR_PROJECT_MEMBER_ZONE_TYPE,
scope_types=['system', 'project'], scope_types=['system', 'project'],
description="Delete RecordSet", description="Delete RecordSet",
operations=[ operations=[

View File

@ -88,9 +88,6 @@ rules = [
description="Show a Tsigkey", description="Show a Tsigkey",
operations=[ operations=[
{ {
'path': '/v2/tsigkeys/{tsigkey_id}',
'method': 'PATCH'
}, {
'path': '/v2/tsigkeys/{tsigkey_id}', 'path': '/v2/tsigkeys/{tsigkey_id}',
'method': 'GET' 'method': 'GET'
} }

View File

@ -46,6 +46,12 @@ deprecated_get_zone_servers = policy.DeprecatedRule(
deprecated_reason=DEPRECATED_REASON, deprecated_reason=DEPRECATED_REASON,
deprecated_since=versionutils.deprecated.WALLABY deprecated_since=versionutils.deprecated.WALLABY
) )
deprecated_get_zone_ns_records = policy.DeprecatedRule(
name="get_zone_ns_records",
check_str=base.RULE_ADMIN_OR_OWNER,
deprecated_reason=DEPRECATED_REASON,
deprecated_since=versionutils.deprecated.WALLABY
)
deprecated_find_zones = policy.DeprecatedRule( deprecated_find_zones = policy.DeprecatedRule(
name="find_zones", name="find_zones",
check_str=base.RULE_ADMIN_OR_OWNER, check_str=base.RULE_ADMIN_OR_OWNER,
@ -131,12 +137,6 @@ rules = [
{ {
'path': '/v2/zones/{zone_id}', 'path': '/v2/zones/{zone_id}',
'method': 'GET' 'method': 'GET'
}, {
'path': '/v2/zones/{zone_id}',
'method': 'PATCH'
}, {
'path': '/v2/zones/{zone_id}/recordsets/{recordset_id}',
'method': 'PUT'
} }
], ],
deprecated_rule=deprecated_get_zone deprecated_rule=deprecated_get_zone
@ -147,6 +147,19 @@ rules = [
scope_types=['system', 'project'], scope_types=['system', 'project'],
deprecated_rule=deprecated_get_zone_servers deprecated_rule=deprecated_get_zone_servers
), ),
policy.DocumentedRuleDefault(
name="get_zone_ns_records",
check_str=base.SYSTEM_OR_PROJECT_READER,
scope_types=['system', 'project'],
description="Get the Name Servers for a Zone",
operations=[
{
'path': '/v2/zones/{zone_id}/nameservers',
'method': 'GET'
}
],
deprecated_rule=deprecated_get_zone_ns_records
),
policy.DocumentedRuleDefault( policy.DocumentedRuleDefault(
name="find_zones", name="find_zones",
check_str=base.SYSTEM_OR_PROJECT_READER, check_str=base.SYSTEM_OR_PROJECT_READER,

View File

@ -52,6 +52,12 @@ deprecated_update_zone_export = policy.DeprecatedRule(
deprecated_reason=DEPRECATED_REASON, deprecated_reason=DEPRECATED_REASON,
deprecated_since=versionutils.deprecated.WALLABY deprecated_since=versionutils.deprecated.WALLABY
) )
deprecated_delete_zone_export = policy.DeprecatedRule(
name="delete_zone_export",
check_str=base.RULE_ADMIN_OR_OWNER,
deprecated_reason=DEPRECATED_REASON,
deprecated_since=versionutils.deprecated.WALLABY
)
rules = [ rules = [
@ -103,9 +109,6 @@ rules = [
{ {
'path': '/v2/zones/tasks/exports/{zone_export_id}', 'path': '/v2/zones/tasks/exports/{zone_export_id}',
'method': 'GET' 'method': 'GET'
}, {
'path': '/v2/zones/tasks/exports/{zone_export_id}/export',
'method': 'GET'
} }
], ],
deprecated_rule=deprecated_get_zone_export deprecated_rule=deprecated_get_zone_export
@ -122,7 +125,20 @@ rules = [
} }
], ],
deprecated_rule=deprecated_update_zone_export deprecated_rule=deprecated_update_zone_export
) ),
policy.DocumentedRuleDefault(
name="delete_zone_export",
check_str=base.SYSTEM_ADMIN_OR_PROJECT_MEMBER,
scope_types=['system', 'project'],
description="Delete a zone export",
operations=[
{
'path': '/v2/zones/tasks/exports/{zone_export_id}',
'method': 'DELETE'
}
],
deprecated_rule=deprecated_delete_zone_export
),
] ]

View File

@ -115,7 +115,7 @@ rules = [
operations=[ operations=[
{ {
'path': '/v2/zones/tasks/imports/{zone_import_id}', 'path': '/v2/zones/tasks/imports/{zone_import_id}',
'method': 'GET' 'method': 'DELETE'
} }
], ],
deprecated_rule=deprecated_delete_zone_import deprecated_rule=deprecated_delete_zone_import

View File

@ -24,7 +24,7 @@ The zone transfer accept API now supports system scope and default roles.
deprecated_create_zone_transfer_accept = policy.DeprecatedRule( deprecated_create_zone_transfer_accept = policy.DeprecatedRule(
name="create_zone_transfer_accept", name="create_zone_transfer_accept",
check_str=base.RULE_ZONE_TRANSFER, check_str=base.LEGACY_RULE_ZONE_TRANSFER,
deprecated_reason=DEPRECATED_REASON, deprecated_reason=DEPRECATED_REASON,
deprecated_since=versionutils.deprecated.WALLABY deprecated_since=versionutils.deprecated.WALLABY
) )
@ -64,13 +64,15 @@ rules = [
policy.DocumentedRuleDefault( policy.DocumentedRuleDefault(
name="create_zone_transfer_accept", name="create_zone_transfer_accept",
check_str=base.RULE_ZONE_TRANSFER, check_str=base.RULE_ZONE_TRANSFER,
scope_types=['system', 'project'],
description="Create Zone Transfer Accept", description="Create Zone Transfer Accept",
operations=[ operations=[
{ {
'path': '/v2/zones/tasks/transfer_accepts', 'path': '/v2/zones/tasks/transfer_accepts',
'method': 'POST' 'method': 'POST'
} }
] ],
deprecated_rule=deprecated_create_zone_transfer_accept
), ),
policy.DocumentedRuleDefault( policy.DocumentedRuleDefault(
name="get_zone_transfer_accept", name="get_zone_transfer_accept",

View File

@ -30,7 +30,7 @@ deprecated_create_zone_transfer_request = policy.DeprecatedRule(
) )
deprecated_get_zone_transfer_request = policy.DeprecatedRule( deprecated_get_zone_transfer_request = policy.DeprecatedRule(
name="get_zone_transfer_request", name="get_zone_transfer_request",
check_str=base.RULE_ZONE_TRANSFER, check_str=base.LEGACY_RULE_ZONE_TRANSFER,
deprecated_reason=DEPRECATED_REASON, deprecated_reason=DEPRECATED_REASON,
deprecated_since=versionutils.deprecated.WALLABY deprecated_since=versionutils.deprecated.WALLABY
) )
@ -40,12 +40,6 @@ deprecated_get_zone_transfer_request_detailed = policy.DeprecatedRule(
deprecated_reason=DEPRECATED_REASON, deprecated_reason=DEPRECATED_REASON,
deprecated_since=versionutils.deprecated.WALLABY deprecated_since=versionutils.deprecated.WALLABY
) )
deprecated_find_zone_transfer_requests = policy.DeprecatedRule(
name="find_zone_transfer_requests",
check_str=base.RULE_ANY,
deprecated_reason=DEPRECATED_REASON,
deprecated_since=versionutils.deprecated.WALLABY
)
deprecated_update_zone_transfer_request = policy.DeprecatedRule( deprecated_update_zone_transfer_request = policy.DeprecatedRule(
name="update_zone_transfer_request", name="update_zone_transfer_request",
check_str=base.RULE_ADMIN_OR_OWNER, check_str=base.RULE_ADMIN_OR_OWNER,
@ -77,16 +71,15 @@ rules = [
policy.DocumentedRuleDefault( policy.DocumentedRuleDefault(
name="get_zone_transfer_request", name="get_zone_transfer_request",
check_str=base.RULE_ZONE_TRANSFER, check_str=base.RULE_ZONE_TRANSFER,
scope_types=['system', 'project'],
description="Show a Zone Transfer Request", description="Show a Zone Transfer Request",
operations=[ operations=[
{ {
'path': '/v2/zones/tasks/transfer_requests/{zone_transfer_request_id}', # noqa 'path': '/v2/zones/tasks/transfer_requests/{zone_transfer_request_id}', # noqa
'method': 'GET' 'method': 'GET'
}, {
'path': '/v2/zones/tasks/transfer_requests/{zone_transfer_request_id}', # noqa
'method': 'PATCH'
} }
] ],
deprecated_rule=deprecated_get_zone_transfer_request
), ),
policy.RuleDefault( policy.RuleDefault(
name="get_zone_transfer_request_detailed", name="get_zone_transfer_request_detailed",
@ -103,7 +96,7 @@ rules = [
'path': '/v2/zones/tasks/transfer_requests', 'path': '/v2/zones/tasks/transfer_requests',
'method': 'GET' 'method': 'GET'
} }
] ],
), ),
policy.RuleDefault( policy.RuleDefault(
name="find_zone_transfer_request", name="find_zone_transfer_request",

View File

@ -107,6 +107,8 @@ class DesignateContext(context.RequestContext):
# NOTE(kiall): Ugly - required to match http://tinyurl.com/o3y8qmw # NOTE(kiall): Ugly - required to match http://tinyurl.com/o3y8qmw
context.roles.append('admin') context.roles.append('admin')
if policy.enforce_new_defaults():
context.system_scope = 'all'
if show_deleted is not None: if show_deleted is not None:
context.show_deleted = show_deleted context.show_deleted = show_deleted
@ -132,7 +134,8 @@ class DesignateContext(context.RequestContext):
def get_admin_context(cls, **kwargs): def get_admin_context(cls, **kwargs):
# TODO(kiall): Remove Me # TODO(kiall): Remove Me
kwargs['is_admin'] = True kwargs['is_admin'] = True
kwargs['roles'] = ['admin'] kwargs['roles'] = ['admin', 'reader']
kwargs['system_scope'] = 'all'
return cls(None, **kwargs) return cls(None, **kwargs)

View File

@ -256,6 +256,10 @@ class IncorrectZoneTransferKey(Forbidden):
error_type = 'invalid_key' error_type = 'invalid_key'
class InvalidTokenScope(Forbidden):
error_type = 'invalid_token_scope'
class Duplicate(DesignateException): class Duplicate(DesignateException):
expected = True expected = True
error_code = 409 error_code = 409
@ -473,3 +477,12 @@ class LastServerDeleteNotAllowed(BadRequest):
class ResourceNotFound(NotFound): class ResourceNotFound(NotFound):
# TODO(kiall): Should this be extending NotFound?? # TODO(kiall): Should this be extending NotFound??
pass pass
class MissingProjectID(BadRequest):
# Note: This should be 400, but is 401 for compatibility with
# previous versions of the API.
# https://github.com/openstack/designate/blob/stable/wallaby/ \
# designate/api/middleware.py#L132
error_code = 401
error_type = 'missing_project_id'

View File

@ -11,6 +11,7 @@
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the # WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
# License for the specific language governing permissions and limitations # License for the specific language governing permissions and limitations
# under the License. # under the License.
from designate.common import constants
from designate import exceptions from designate import exceptions
from designate import objects from designate import objects
from designate.objects.adapters.api_v2 import base from designate.objects.adapters.api_v2 import base
@ -65,9 +66,10 @@ class ZoneTransferRequestAPIv2Adapter(base.APIv2Adapter):
object, *args, **kwargs) object, *args, **kwargs)
try: try:
target = { if policy.enforce_new_defaults():
'tenant_id': object.tenant_id, target = {constants.RBAC_PROJECT_ID: object.tenant_id}
} else:
target = {'tenant_id': object.tenant_id}
policy.check( policy.check(
'get_zone_transfer_request_detailed', 'get_zone_transfer_request_detailed',

View File

@ -73,10 +73,17 @@ def init(default_rule=None, policy_file=None):
def check(rule, ctxt, target=None, do_raise=True, exc=exceptions.Forbidden): def check(rule, ctxt, target=None, do_raise=True, exc=exceptions.Forbidden):
if enforce_new_defaults():
creds = ctxt.to_policy_values()
else:
creds = ctxt.to_dict() creds = ctxt.to_dict()
target = target or {} target = target or {}
try: try:
result = _ENFORCER.enforce(rule, target, creds, do_raise, exc) result = _ENFORCER.enforce(rule, target, creds, do_raise, exc)
except policy.InvalidScope:
result = False
if do_raise:
raise exceptions.InvalidTokenScope
except Exception: except Exception:
result = False result = False
raise raise
@ -93,3 +100,9 @@ def check(rule, ctxt, target=None, do_raise=True, exc=exceptions.Forbidden):
LOG.info("Policy check failed for rule '%(rule)s' " LOG.info("Policy check failed for rule '%(rule)s' "
"on target %(target)s", "on target %(target)s",
{'rule': rule, 'target': repr(target)}, extra=extra) {'rule': rule, 'target': repr(target)}, extra=extra)
def enforce_new_defaults():
if CONF.get('oslo_policy'):
return CONF['oslo_policy'].get('enforce_new_defaults', False)
return False

View File

@ -1488,6 +1488,12 @@ class SQLAlchemyStorage(sqlalchemy_base.SQLAlchemy, storage_base.Storage):
).select_from(ljoin) ).select_from(ljoin)
if not context.all_tenants: if not context.all_tenants:
# If we have a system scoped token with no project_id and
# all_tenants was not used, we don't know what records to return,
# so return an empty list.
if not context.project_id:
return objects.ZoneTransferRequestList()
query = query.where(or_( query = query.where(or_(
table.c.tenant_id == context.project_id, table.c.tenant_id == context.project_id,
table.c.target_tenant_id == context.project_id)) table.c.target_tenant_id == context.project_id))
@ -1498,7 +1504,8 @@ class SQLAlchemyStorage(sqlalchemy_base.SQLAlchemy, storage_base.Storage):
exceptions.ZoneTransferRequestNotFound, exceptions.ZoneTransferRequestNotFound,
criterion, criterion,
one=one, marker=marker, limit=limit, sort_dir=sort_dir, one=one, marker=marker, limit=limit, sort_dir=sort_dir,
sort_key=sort_key, query=query, apply_tenant_criteria=False sort_key=sort_key, query=query,
apply_tenant_criteria=False
) )
def create_zone_transfer_request(self, context, zone_transfer_request): def create_zone_transfer_request(self, context, zone_transfer_request):

View File

@ -387,6 +387,8 @@ class TestCase(base.BaseTestCase):
self.central_service = self.start_service('central') self.central_service = self.start_service('central')
self.admin_context = self.get_admin_context() self.admin_context = self.get_admin_context()
self.admin_context_all_tenants = self.get_admin_context(
all_tenants=True)
storage_driver = CONF['service:central'].storage_driver storage_driver = CONF['service:central'].storage_driver
self.storage = storage.get_storage(storage_driver) self.storage = storage.get_storage(storage_driver)
@ -436,10 +438,11 @@ class TestCase(base.BaseTestCase):
def get_context(self, **kwargs): def get_context(self, **kwargs):
return DesignateContext(**kwargs) return DesignateContext(**kwargs)
def get_admin_context(self): def get_admin_context(self, **kwargs):
return DesignateContext.get_admin_context( return DesignateContext.get_admin_context(
project_id=utils.generate_uuid(), project_id=utils.generate_uuid(),
user_id=utils.generate_uuid()) user_id=utils.generate_uuid(),
**kwargs)
# Fixture methods # Fixture methods
def get_quota_fixture(self, fixture=0, values=None): def get_quota_fixture(self, fixture=0, values=None):
@ -794,7 +797,7 @@ class TestCase(base.BaseTestCase):
# Retrieve it, and ensure it's the same # Retrieve it, and ensure it's the same
zone_import = self.central_service.get_zone_import( zone_import = self.central_service.get_zone_import(
self.admin_context, zone_import_id) self.admin_context_all_tenants, zone_import_id)
# If the import is done, we're done # If the import is done, we're done
if zone_import.status == 'COMPLETE': if zone_import.status == 'COMPLETE':

View File

@ -102,7 +102,8 @@ class KeystoneContextMiddlewareTest(ApiTestCase):
# Process the request # Process the request
response = app(request) response = app(request)
self.assertEqual(401, response.status_code) # Ensure request was not blocked
self.assertEqual(response, 'FakeResponse')
class NoAuthContextMiddlewareTest(ApiTestCase): class NoAuthContextMiddlewareTest(ApiTestCase):

View File

@ -36,6 +36,7 @@ from designate import objects
from designate.storage.impl_sqlalchemy import tables from designate.storage.impl_sqlalchemy import tables
from designate.tests import fixtures from designate.tests import fixtures
from designate.tests.test_central import CentralTestCase from designate.tests.test_central import CentralTestCase
from designate import utils
LOG = logging.getLogger(__name__) LOG = logging.getLogger(__name__)
@ -3537,7 +3538,7 @@ class CentralServiceTest(CentralTestCase):
# Zone Import Tests # Zone Import Tests
def test_create_zone_import(self): def test_create_zone_import(self):
# Create a Zone Import # Create a Zone Import
context = self.get_context() context = self.get_context(project_id=utils.generate_uuid())
request_body = self.get_zonefile_fixture() request_body = self.get_zonefile_fixture()
zone_import = self.central_service.create_zone_import(context, zone_import = self.central_service.create_zone_import(context,
request_body) request_body)
@ -3551,7 +3552,7 @@ class CentralServiceTest(CentralTestCase):
self.wait_for_import(zone_import.id) self.wait_for_import(zone_import.id)
def test_find_zone_imports(self): def test_find_zone_imports(self):
context = self.get_context() context = self.get_context(project_id=utils.generate_uuid())
# Ensure we have no zone_imports to start with. # Ensure we have no zone_imports to start with.
zone_imports = self.central_service.find_zone_imports( zone_imports = self.central_service.find_zone_imports(
@ -3568,7 +3569,7 @@ class CentralServiceTest(CentralTestCase):
# Ensure we can retrieve the newly created zone_import # Ensure we can retrieve the newly created zone_import
zone_imports = self.central_service.find_zone_imports( zone_imports = self.central_service.find_zone_imports(
self.admin_context) self.admin_context_all_tenants)
self.assertEqual(1, len(zone_imports)) self.assertEqual(1, len(zone_imports))
# Create a second zone_import # Create a second zone_import
@ -3581,14 +3582,14 @@ class CentralServiceTest(CentralTestCase):
# Ensure we can retrieve both zone_imports # Ensure we can retrieve both zone_imports
zone_imports = self.central_service.find_zone_imports( zone_imports = self.central_service.find_zone_imports(
self.admin_context) self.admin_context_all_tenants)
self.assertEqual(2, len(zone_imports)) self.assertEqual(2, len(zone_imports))
self.assertEqual('COMPLETE', zone_imports[0].status) self.assertEqual('COMPLETE', zone_imports[0].status)
self.assertEqual('COMPLETE', zone_imports[1].status) self.assertEqual('COMPLETE', zone_imports[1].status)
def test_get_zone_import(self): def test_get_zone_import(self):
# Create a Zone Import # Create a Zone Import
context = self.get_context() context = self.get_context(project_id=utils.generate_uuid())
request_body = self.get_zonefile_fixture() request_body = self.get_zonefile_fixture()
zone_import = self.central_service.create_zone_import( zone_import = self.central_service.create_zone_import(
context, request_body) context, request_body)
@ -3598,7 +3599,7 @@ class CentralServiceTest(CentralTestCase):
# Retrieve it, and ensure it's the same # Retrieve it, and ensure it's the same
zone_import = self.central_service.get_zone_import( zone_import = self.central_service.get_zone_import(
self.admin_context, zone_import.id) self.admin_context_all_tenants, zone_import.id)
self.assertEqual(zone_import.id, zone_import['id']) self.assertEqual(zone_import.id, zone_import['id'])
self.assertEqual(zone_import.status, zone_import['status']) self.assertEqual(zone_import.status, zone_import['status'])
@ -3606,7 +3607,7 @@ class CentralServiceTest(CentralTestCase):
def test_update_zone_import(self): def test_update_zone_import(self):
# Create a Zone Import # Create a Zone Import
context = self.get_context() context = self.get_context(project_id=utils.generate_uuid())
request_body = self.get_zonefile_fixture() request_body = self.get_zonefile_fixture()
zone_import = self.central_service.create_zone_import( zone_import = self.central_service.create_zone_import(
context, request_body) context, request_body)
@ -3618,7 +3619,7 @@ class CentralServiceTest(CentralTestCase):
# Perform the update # Perform the update
zone_import = self.central_service.update_zone_import( zone_import = self.central_service.update_zone_import(
self.admin_context, zone_import) self.admin_context_all_tenants, zone_import)
# Fetch the zone_import again # Fetch the zone_import again
zone_import = self.central_service.get_zone_import(context, zone_import = self.central_service.get_zone_import(context,
@ -3629,7 +3630,7 @@ class CentralServiceTest(CentralTestCase):
def test_delete_zone_import(self): def test_delete_zone_import(self):
# Create a Zone Import # Create a Zone Import
context = self.get_context() context = self.get_context(project_id=utils.generate_uuid())
request_body = self.get_zonefile_fixture() request_body = self.get_zonefile_fixture()
zone_import = self.central_service.create_zone_import( zone_import = self.central_service.create_zone_import(
context, request_body) context, request_body)

View File

@ -256,6 +256,7 @@ class CentralBasic(TestCase):
'set_rules', 'set_rules',
'init', 'init',
'check', 'check',
'enforce_new_defaults',
]) ])
designate.central.service.quota = mock.NonCallableMock(spec_set=[ designate.central.service.quota = mock.NonCallableMock(spec_set=[
@ -932,7 +933,7 @@ class CentralZoneTestCase(CentralBasic):
n, ctx, target = designate.central.service.policy.check.call_args[0] n, ctx, target = designate.central.service.policy.check.call_args[0]
self.assertEqual(CentralZoneTestCase.zone__id, target['zone_id']) self.assertEqual(CentralZoneTestCase.zone__id, target['zone_id'])
self.assertEqual('foo', target['zone_name']) self.assertEqual('foo', target['zone_name'])
self.assertEqual('2', target['tenant_id']) self.assertEqual('2', target['project_id'])
def test_get_zone_servers(self): def test_get_zone_servers(self):
self.service.storage.get_zone.return_value = RoObject( self.service.storage.get_zone.return_value = RoObject(
@ -995,6 +996,7 @@ class CentralZoneTestCase(CentralBasic):
'set_rules', 'set_rules',
'init', 'init',
'check', 'check',
'enforce_new_defaults',
]) ])
self.context.abandon = True self.context.abandon = True
self.service.storage.count_zones.return_value = 0 self.service.storage.count_zones.return_value = 0
@ -1187,7 +1189,7 @@ class CentralZoneTestCase(CentralBasic):
'zone_id': CentralZoneTestCase.zone__id_2, 'zone_id': CentralZoneTestCase.zone__id_2,
'zone_name': 'example.org.', 'zone_name': 'example.org.',
'recordset_id': CentralZoneTestCase.recordset__id, 'recordset_id': CentralZoneTestCase.recordset__id,
'tenant_id': '2'}, target) 'project_id': '2'}, target)
def test_find_recordsets(self): def test_find_recordsets(self):
self.context = mock.Mock() self.context = mock.Mock()
@ -1196,7 +1198,7 @@ class CentralZoneTestCase(CentralBasic):
self.assertTrue(self.service.storage.find_recordsets.called) self.assertTrue(self.service.storage.find_recordsets.called)
n, ctx, target = designate.central.service.policy.check.call_args[0] n, ctx, target = designate.central.service.policy.check.call_args[0]
self.assertEqual('find_recordsets', n) self.assertEqual('find_recordsets', n)
self.assertEqual({'tenant_id': 't'}, target) self.assertEqual({'project_id': 't'}, target)
def test_find_recordset(self): def test_find_recordset(self):
self.context = mock.Mock() self.context = mock.Mock()
@ -1205,7 +1207,7 @@ class CentralZoneTestCase(CentralBasic):
self.assertTrue(self.service.storage.find_recordset.called) self.assertTrue(self.service.storage.find_recordset.called)
n, ctx, target = designate.central.service.policy.check.call_args[0] n, ctx, target = designate.central.service.policy.check.call_args[0]
self.assertEqual('find_recordset', n) self.assertEqual('find_recordset', n)
self.assertEqual({'tenant_id': 't'}, target) self.assertEqual({'project_id': 't'}, target)
def test_update_recordset_fail_on_changes(self): def test_update_recordset_fail_on_changes(self):
self.service.storage.get_zone.return_value = RoObject() self.service.storage.get_zone.return_value = RoObject()
@ -1298,7 +1300,7 @@ class CentralZoneTestCase(CentralBasic):
'zone_name': 'example.org.', 'zone_name': 'example.org.',
'zone_type': 'foo', 'zone_type': 'foo',
'recordset_id': '9c85d9b0-1e9d-4e99-aede-a06664f1af2e', 'recordset_id': '9c85d9b0-1e9d-4e99-aede-a06664f1af2e',
'tenant_id': '2'}, target) 'project_id': '2'}, target)
def test__update_recordset_in_storage(self): def test__update_recordset_in_storage(self):
recordset = mock.Mock() recordset = mock.Mock()
@ -1532,7 +1534,7 @@ class CentralZoneTestCase(CentralBasic):
self.service.count_recordsets(self.context) self.service.count_recordsets(self.context)
n, ctx, target = designate.central.service.policy.check.call_args[0] n, ctx, target = designate.central.service.policy.check.call_args[0]
self.assertEqual('count_recordsets', n) self.assertEqual('count_recordsets', n)
self.assertEqual({'tenant_id': None}, target) self.assertEqual({'project_id': None}, target)
self.assertEqual( self.assertEqual(
{}, {},
self.service.storage.count_recordsets.call_args[0][1] self.service.storage.count_recordsets.call_args[0][1]
@ -1587,7 +1589,7 @@ class CentralZoneTestCase(CentralBasic):
'zone_type': 'foo', 'zone_type': 'foo',
'recordset_id': CentralZoneTestCase.recordset__id, 'recordset_id': CentralZoneTestCase.recordset__id,
'recordset_name': 'rs', 'recordset_name': 'rs',
'tenant_id': '2'}, target) 'project_id': '2'}, target)
def test_create_record_worker(self): def test_create_record_worker(self):
self._test_create_record() self._test_create_record()
@ -1689,7 +1691,7 @@ class CentralZoneTestCase(CentralBasic):
'record_id': CentralZoneTestCase.record__id, 'record_id': CentralZoneTestCase.record__id,
'recordset_id': CentralZoneTestCase.recordset__id_2, 'recordset_id': CentralZoneTestCase.recordset__id_2,
'recordset_name': 'foo', 'recordset_name': 'foo',
'tenant_id': 2}, target) 'project_id': 2}, target)
def test_update_record_fail_on_changes(self): def test_update_record_fail_on_changes(self):
self.service.storage.get_zone.return_value = RoObject( self.service.storage.get_zone.return_value = RoObject(
@ -1789,7 +1791,7 @@ class CentralZoneTestCase(CentralBasic):
'record_id': 'abc12a-1e9d-4e99-aede-a06664f1af2e', 'record_id': 'abc12a-1e9d-4e99-aede-a06664f1af2e',
'recordset_id': 'abc12a-1e9d-4e99-aede-a06664f1af2e', 'recordset_id': 'abc12a-1e9d-4e99-aede-a06664f1af2e',
'recordset_name': 'rsn', 'recordset_name': 'rsn',
'tenant_id': 'tid'}, target) 'project_id': 'tid'}, target)
def test__update_record_in_storage(self): def test__update_record_in_storage(self):
self.service._update_zone_in_storage = mock.Mock() self.service._update_zone_in_storage = mock.Mock()
@ -1893,7 +1895,7 @@ class CentralZoneTestCase(CentralBasic):
'record_id': CentralZoneTestCase.record__id_2, 'record_id': CentralZoneTestCase.record__id_2,
'recordset_id': CentralZoneTestCase.recordset__id_2, 'recordset_id': CentralZoneTestCase.recordset__id_2,
'recordset_name': 'rsn', 'recordset_name': 'rsn',
'tenant_id': 'tid'}, target) 'project_id': 'tid'}, target)
def test_delete_record_in_storage(self): def test_delete_record_in_storage(self):
self.service._delete_record_in_storage( self.service._delete_record_in_storage(
@ -1911,7 +1913,7 @@ class CentralZoneTestCase(CentralBasic):
self.service.count_records(self.context) self.service.count_records(self.context)
t, ctx, target = designate.central.service.policy.check.call_args[0] t, ctx, target = designate.central.service.policy.check.call_args[0]
self.assertEqual('count_records', t) self.assertEqual('count_records', t)
self.assertEqual({'tenant_id': None}, target) self.assertEqual({'project_id': None}, target)
def test_sync_zones(self): def test_sync_zones(self):
self.service._sync_zone = mock.Mock() self.service._sync_zone = mock.Mock()
@ -1938,7 +1940,7 @@ class CentralZoneTestCase(CentralBasic):
t, ctx, target = designate.central.service.policy.check.call_args[0] t, ctx, target = designate.central.service.policy.check.call_args[0]
self.assertEqual('diagnostics_sync_zone', t) self.assertEqual('diagnostics_sync_zone', t)
self.assertEqual({'tenant_id': 'tid', self.assertEqual({'project_id': 'tid',
'zone_id': CentralZoneTestCase.zone__id, 'zone_id': CentralZoneTestCase.zone__id,
'zone_name': 'n'}, target) 'zone_name': 'n'}, target)
@ -1965,7 +1967,7 @@ class CentralZoneTestCase(CentralBasic):
'record_id': CentralZoneTestCase.record__id, 'record_id': CentralZoneTestCase.record__id,
'recordset_id': CentralZoneTestCase.recordset__id, 'recordset_id': CentralZoneTestCase.recordset__id,
'recordset_name': 'n', 'recordset_name': 'n',
'tenant_id': 'tid'}, target) 'project_id': 'tid'}, target)
def test_ping(self): def test_ping(self):
self.service.storage.ping.return_value = True self.service.storage.ping.return_value = True
@ -2118,7 +2120,7 @@ class CentralZoneExportTests(CentralBasic):
n, ctx, target = designate.central.service.policy.check.call_args[0] n, ctx, target = designate.central.service.policy.check.call_args[0]
# Check arguments to policy # Check arguments to policy
self.assertEqual('t', target['tenant_id']) self.assertEqual('t', target['project_id'])
# Check output # Check output
self.assertEqual(CentralZoneTestCase.zone__id, out.zone_id) self.assertEqual(CentralZoneTestCase.zone__id, out.zone_id)

View File

@ -0,0 +1,4 @@
---
features:
- |
Adds support for keystone default roles and scoped tokens.