Get initiator from manager and send to controller

Using the WSGI context that is available at the manager layer,
we can get the Initiator content we need and forward it to the manager
classes.

Co-Authored-By: Morgan Fainberg <morgan.fainberg@gmail.com>
partially implements bp: cadf-everywhere

Change-Id: I6b7885d29cd733c5040bea6003dd93607cb5821e
This commit is contained in:
Steve Martinelli 2015-01-31 02:24:57 -05:00
parent bc7fcca3af
commit ffcc81b7a6
11 changed files with 174 additions and 102 deletions

View File

@ -30,6 +30,7 @@ from keystone.common import validation
from keystone import exception
from keystone.i18n import _, _LW
from keystone.models import token_model
from keystone import notifications
CONF = cfg.CONF
@ -282,7 +283,8 @@ class RoleV3(controller.V3Controller):
@validation.validated(schema.role_create, 'role')
def create_role(self, context, role):
ref = self._assign_unique_id(self._normalize_dict(role))
ref = self.role_api.create_role(ref['id'], ref)
initiator = notifications._get_request_audit_info(context)
ref = self.role_api.create_role(ref['id'], ref, initiator)
return RoleV3.wrap_member(context, ref)
@controller.filterprotected('name')
@ -301,13 +303,14 @@ class RoleV3(controller.V3Controller):
@validation.validated(schema.role_update, 'role')
def update_role(self, context, role_id, role):
self._require_matching_id(role_id, role)
ref = self.role_api.update_role(role_id, role)
initiator = notifications._get_request_audit_info(context)
ref = self.role_api.update_role(role_id, role, initiator)
return RoleV3.wrap_member(context, ref)
@controller.protected()
def delete_role(self, context, role_id):
self.role_api.delete_role(role_id)
initiator = notifications._get_request_audit_info(context)
self.role_api.delete_role(role_id, initiator)
@dependency.requires('assignment_api', 'identity_api', 'resource_api',

View File

@ -916,9 +916,9 @@ class RoleManager(manager.Manager):
def get_role(self, role_id):
return self.driver.get_role(role_id)
@notifications.created(_ROLE)
def create_role(self, role_id, role):
def create_role(self, role_id, role, initiator=None):
ret = self.driver.create_role(role_id, role)
notifications.Audit.created(self._ROLE, role_id, initiator)
if SHOULD_CACHE(ret):
self.get_role.set(ret, self, role_id)
return ret
@ -927,17 +927,28 @@ class RoleManager(manager.Manager):
def list_roles(self, hints=None):
return self.driver.list_roles(hints or driver_hints.Hints())
@notifications.updated(_ROLE)
def update_role(self, role_id, role):
def update_role(self, role_id, role, initiator=None):
ret = self.driver.update_role(role_id, role)
notifications.Audit.updated(self._ROLE, role_id, initiator)
self.get_role.invalidate(self, role_id)
return ret
@notifications.deleted(_ROLE)
def delete_role(self, role_id):
self.assignment_api.delete_tokens_for_role_assignments(role_id)
def delete_role(self, role_id, initiator=None):
try:
self.assignment_api.delete_tokens_for_role_assignments(role_id)
except exception.NotImplemented:
# FIXME(morganfainberg): Not all backends (ldap) implement
# `list_role_assignments_for_role` which would have previously
# caused a NotImplmented error to be raised when called through
# the controller. Now error or proper action will always come from
# the `delete_role` method logic. Work needs to be done to make
# the behavior between drivers consistent (capable of revoking
# tokens for the same circumstances). This is related to the bug
# https://bugs.launchpad.net/keystone/+bug/1221805
pass
self.assignment_api.delete_role_assignments(role_id)
self.driver.delete_role(role_id)
notifications.Audit.deleted(self._ROLE, role_id, initiator)
self.get_role.invalidate(self, role_id)

View File

@ -24,6 +24,7 @@ from keystone.common import validation
from keystone.common import wsgi
from keystone import exception
from keystone.i18n import _
from keystone import notifications
INTERFACES = ['public', 'internal', 'admin']
@ -99,12 +100,14 @@ class Endpoint(controller.V2Controller):
# service_id is necessary
self._require_attribute(endpoint, 'service_id')
initiator = notifications._get_request_audit_info(context)
if endpoint.get('region') is not None:
try:
self.catalog_api.get_region(endpoint['region'])
except exception.RegionNotFound:
region = dict(id=endpoint['region'])
self.catalog_api.create_region(region)
self.catalog_api.create_region(region, initiator)
legacy_endpoint_ref = endpoint.copy()
@ -128,8 +131,8 @@ class Endpoint(controller.V2Controller):
endpoint_ref['interface'] = interface
endpoint_ref['url'] = url
endpoint_ref['region_id'] = endpoint_ref.pop('region')
self.catalog_api.create_endpoint(endpoint_ref['id'], endpoint_ref)
self.catalog_api.create_endpoint(endpoint_ref['id'], endpoint_ref,
initiator)
legacy_endpoint_ref['id'] = legacy_endpoint_id
return {'endpoint': legacy_endpoint_ref}
@ -177,7 +180,8 @@ class RegionV3(controller.V3Controller):
if not ref.get('id'):
ref = self._assign_unique_id(ref)
ref = self.catalog_api.create_region(ref)
initiator = notifications._get_request_audit_info(context)
ref = self.catalog_api.create_region(ref, initiator)
return wsgi.render_response(
RegionV3.wrap_member(context, ref),
status=(201, 'Created'))
@ -197,13 +201,14 @@ class RegionV3(controller.V3Controller):
@validation.validated(schema.region_update, 'region')
def update_region(self, context, region_id, region):
self._require_matching_id(region_id, region)
ref = self.catalog_api.update_region(region_id, region)
initiator = notifications._get_request_audit_info(context)
ref = self.catalog_api.update_region(region_id, region, initiator)
return RegionV3.wrap_member(context, ref)
@controller.protected()
def delete_region(self, context, region_id):
return self.catalog_api.delete_region(region_id)
initiator = notifications._get_request_audit_info(context)
return self.catalog_api.delete_region(region_id, initiator)
@dependency.requires('catalog_api')
@ -219,8 +224,8 @@ class ServiceV3(controller.V3Controller):
@validation.validated(schema.service_create, 'service')
def create_service(self, context, service):
ref = self._assign_unique_id(self._normalize_dict(service))
ref = self.catalog_api.create_service(ref['id'], ref)
initiator = notifications._get_request_audit_info(context)
ref = self.catalog_api.create_service(ref['id'], ref, initiator)
return ServiceV3.wrap_member(context, ref)
@controller.filterprotected('type', 'name')
@ -238,13 +243,14 @@ class ServiceV3(controller.V3Controller):
@validation.validated(schema.service_update, 'service')
def update_service(self, context, service_id, service):
self._require_matching_id(service_id, service)
ref = self.catalog_api.update_service(service_id, service)
initiator = notifications._get_request_audit_info(context)
ref = self.catalog_api.update_service(service_id, service, initiator)
return ServiceV3.wrap_member(context, ref)
@controller.protected()
def delete_service(self, context, service_id):
return self.catalog_api.delete_service(service_id)
initiator = notifications._get_request_audit_info(context)
return self.catalog_api.delete_service(service_id, initiator)
@dependency.requires('catalog_api')
@ -268,7 +274,7 @@ class EndpointV3(controller.V3Controller):
ref = cls.filter_endpoint(ref)
return super(EndpointV3, cls).wrap_member(context, ref)
def _validate_endpoint_region(self, endpoint):
def _validate_endpoint_region(self, endpoint, context=None):
"""Ensure the region for the endpoint exists.
If 'region_id' is used to specify the region, then we will let the
@ -287,7 +293,8 @@ class EndpointV3(controller.V3Controller):
self.catalog_api.get_region(endpoint['region_id'])
except exception.RegionNotFound:
region = dict(id=endpoint['region_id'])
self.catalog_api.create_region(region)
initiator = notifications._get_request_audit_info(context)
self.catalog_api.create_region(region, initiator)
return endpoint
@ -296,9 +303,9 @@ class EndpointV3(controller.V3Controller):
def create_endpoint(self, context, endpoint):
ref = self._assign_unique_id(self._normalize_dict(endpoint))
self.catalog_api.get_service(ref['service_id'])
ref = self._validate_endpoint_region(ref)
ref = self.catalog_api.create_endpoint(ref['id'], ref)
ref = self._validate_endpoint_region(ref, context)
initiator = notifications._get_request_audit_info(context)
ref = self.catalog_api.create_endpoint(ref['id'], ref, initiator)
return EndpointV3.wrap_member(context, ref)
@controller.filterprotected('interface', 'service_id')
@ -319,11 +326,14 @@ class EndpointV3(controller.V3Controller):
if 'service_id' in endpoint:
self.catalog_api.get_service(endpoint['service_id'])
endpoint = self._validate_endpoint_region(endpoint.copy())
endpoint = self._validate_endpoint_region(endpoint.copy(), context)
ref = self.catalog_api.update_endpoint(endpoint_id, endpoint)
initiator = notifications._get_request_audit_info(context)
ref = self.catalog_api.update_endpoint(endpoint_id, endpoint,
initiator)
return EndpointV3.wrap_member(context, ref)
@controller.protected()
def delete_endpoint(self, context, endpoint_id):
return self.catalog_api.delete_endpoint(endpoint_id)
initiator = notifications._get_request_audit_info(context)
return self.catalog_api.delete_endpoint(endpoint_id, initiator)

View File

@ -95,8 +95,7 @@ class Manager(manager.Manager):
def __init__(self):
super(Manager, self).__init__(CONF.catalog.driver)
@notifications.created(_REGION, result_id_arg_attr='id')
def create_region(self, region_ref):
def create_region(self, region_ref, initiator=None):
# Check duplicate ID
try:
self.get_region(region_ref['id'])
@ -111,11 +110,14 @@ class Manager(manager.Manager):
# set it to an empty string.
region_ref.setdefault('description', '')
try:
return self.driver.create_region(region_ref)
ret = self.driver.create_region(region_ref)
except exception.NotFound:
parent_region_id = region_ref.get('parent_region_id')
raise exception.RegionNotFound(region_id=parent_region_id)
notifications.Audit.created(self._REGION, ret['id'], initiator)
return ret
@cache.on_arguments(should_cache_fn=SHOULD_CACHE,
expiration_time=EXPIRATION_TIME)
def get_region(self, region_id):
@ -124,16 +126,16 @@ class Manager(manager.Manager):
except exception.NotFound:
raise exception.RegionNotFound(region_id=region_id)
@notifications.updated(_REGION)
def update_region(self, region_id, region_ref):
def update_region(self, region_id, region_ref, initiator=None):
ref = self.driver.update_region(region_id, region_ref)
notifications.Audit.updated(self._REGION, region_id, initiator)
self.get_region.invalidate(self, region_id)
return ref
@notifications.deleted(_REGION)
def delete_region(self, region_id):
def delete_region(self, region_id, initiator=None):
try:
ret = self.driver.delete_region(region_id)
notifications.Audit.deleted(self._REGION, region_id, initiator)
self.get_region.invalidate(self, region_id)
return ret
except exception.NotFound:
@ -143,10 +145,11 @@ class Manager(manager.Manager):
def list_regions(self, hints=None):
return self.driver.list_regions(hints or driver_hints.Hints())
@notifications.created(_SERVICE)
def create_service(self, service_id, service_ref):
def create_service(self, service_id, service_ref, initiator=None):
service_ref.setdefault('enabled', True)
return self.driver.create_service(service_id, service_ref)
ref = self.driver.create_service(service_id, service_ref)
notifications.Audit.created(self._SERVICE, service_id, initiator)
return ref
@cache.on_arguments(should_cache_fn=SHOULD_CACHE,
expiration_time=EXPIRATION_TIME)
@ -156,17 +159,17 @@ class Manager(manager.Manager):
except exception.NotFound:
raise exception.ServiceNotFound(service_id=service_id)
@notifications.updated(_SERVICE)
def update_service(self, service_id, service_ref):
def update_service(self, service_id, service_ref, initiator=None):
ref = self.driver.update_service(service_id, service_ref)
notifications.Audit.updated(self._SERVICE, service_id, initiator)
self.get_service.invalidate(self, service_id)
return ref
@notifications.deleted(_SERVICE)
def delete_service(self, service_id):
def delete_service(self, service_id, initiator=None):
try:
endpoints = self.list_endpoints()
ret = self.driver.delete_service(service_id)
notifications.Audit.deleted(self._SERVICE, service_id, initiator)
self.get_service.invalidate(self, service_id)
for endpoint in endpoints:
if endpoint['service_id'] == service_id:
@ -179,10 +182,9 @@ class Manager(manager.Manager):
def list_services(self, hints=None):
return self.driver.list_services(hints or driver_hints.Hints())
@notifications.created(_ENDPOINT)
def create_endpoint(self, endpoint_id, endpoint_ref):
def create_endpoint(self, endpoint_id, endpoint_ref, initiator=None):
try:
return self.driver.create_endpoint(endpoint_id, endpoint_ref)
ref = self.driver.create_endpoint(endpoint_id, endpoint_ref)
except exception.RegionNotFound:
raise exception.ValidationError(attribute='endpoint region_id',
target='region table')
@ -190,16 +192,19 @@ class Manager(manager.Manager):
service_id = endpoint_ref.get('service_id')
raise exception.ServiceNotFound(service_id=service_id)
@notifications.updated(_ENDPOINT)
def update_endpoint(self, endpoint_id, endpoint_ref):
notifications.Audit.created(self._ENDPOINT, endpoint_id, initiator)
return ref
def update_endpoint(self, endpoint_id, endpoint_ref, initiator=None):
ref = self.driver.update_endpoint(endpoint_id, endpoint_ref)
notifications.Audit.updated(self._ENDPOINT, endpoint_id, initiator)
self.get_endpoint.invalidate(self, endpoint_id)
return ref
@notifications.deleted(_ENDPOINT)
def delete_endpoint(self, endpoint_id):
def delete_endpoint(self, endpoint_id, initiator=None):
try:
ret = self.driver.delete_endpoint(endpoint_id)
notifications.Audit.deleted(self._ENDPOINT, endpoint_id, initiator)
self.get_endpoint.invalidate(self, endpoint_id)
return ret
except exception.NotFound:

View File

@ -21,6 +21,7 @@ from keystone.common import controller
from keystone.common import dependency
from keystone import exception
from keystone.i18n import _, _LW
from keystone import notifications
CONF = cfg.CONF
@ -210,7 +211,8 @@ class UserV3(controller.V3Controller):
# The manager layer will generate the unique ID for users
ref = self._normalize_dict(user)
ref = self._normalize_domain_id(context, ref)
ref = self.identity_api.create_user(ref)
initiator = notifications._get_request_audit_info(context)
ref = self.identity_api.create_user(ref, initiator)
return UserV3.wrap_member(context, ref)
@controller.filterprotected('domain_id', 'enabled', 'name')
@ -236,7 +238,8 @@ class UserV3(controller.V3Controller):
self._require_matching_id(user_id, user)
self._require_matching_domain_id(
user_id, user, self.identity_api.get_user)
ref = self.identity_api.update_user(user_id, user)
initiator = notifications._get_request_audit_info(context)
ref = self.identity_api.update_user(user_id, user, initiator)
return UserV3.wrap_member(context, ref)
@controller.protected()
@ -257,7 +260,8 @@ class UserV3(controller.V3Controller):
@controller.protected()
def delete_user(self, context, user_id):
return self.identity_api.delete_user(user_id)
initiator = notifications._get_request_audit_info(context)
return self.identity_api.delete_user(user_id, initiator)
@controller.protected()
def change_password(self, context, user_id, user):
@ -293,7 +297,8 @@ class GroupV3(controller.V3Controller):
# The manager layer will generate the unique ID for groups
ref = self._normalize_dict(group)
ref = self._normalize_domain_id(context, ref)
ref = self.identity_api.create_group(ref)
initiator = notifications._get_request_audit_info(context)
ref = self.identity_api.create_group(ref, initiator)
return GroupV3.wrap_member(context, ref)
@controller.filterprotected('domain_id', 'name')
@ -320,9 +325,11 @@ class GroupV3(controller.V3Controller):
self._require_matching_id(group_id, group)
self._require_matching_domain_id(
group_id, group, self.identity_api.get_group)
ref = self.identity_api.update_group(group_id, group)
initiator = notifications._get_request_audit_info(context)
ref = self.identity_api.update_group(group_id, group, initiator)
return GroupV3.wrap_member(context, ref)
@controller.protected()
def delete_group(self, context, group_id):
self.identity_api.delete_group(group_id)
initiator = notifications._get_request_audit_info(context)
self.identity_api.delete_group(group_id, initiator)

View File

@ -582,10 +582,9 @@ class Manager(manager.Manager):
return self._set_domain_id_and_mapping(
ref, domain_id, driver, mapping.EntityType.USER)
@notifications.created(_USER, result_id_arg_attr='id')
@domains_configured
@exception_translated('user')
def create_user(self, user_ref):
def create_user(self, user_ref, initiator=None):
user = user_ref.copy()
user['name'] = clean.user_name(user['name'])
user.setdefault('enabled', True)
@ -602,6 +601,7 @@ class Manager(manager.Manager):
# that particular driver type.
user['id'] = uuid.uuid4().hex
ref = driver.create_user(user['id'], user)
notifications.Audit.created(self._USER, user['id'], initiator)
return self._set_domain_id_and_mapping(
ref, domain_id, driver, mapping.EntityType.USER)
@ -655,10 +655,9 @@ class Manager(manager.Manager):
return self._set_domain_id_and_mapping(
ref_list, domain_scope, driver, mapping.EntityType.USER)
@notifications.updated(_USER)
@domains_configured
@exception_translated('user')
def update_user(self, user_id, user_ref):
def update_user(self, user_id, user_ref, initiator=None):
old_user_ref = self.get_user(user_id)
user = user_ref.copy()
if 'name' in user:
@ -684,6 +683,8 @@ class Manager(manager.Manager):
ref = driver.update_user(entity_id, user)
notifications.Audit.updated(self._USER, user_id, initiator)
enabled_change = ((user.get('enabled') is False) and
user['enabled'] != old_user_ref.get('enabled'))
if enabled_change or user.get('password') is not None:
@ -692,10 +693,9 @@ class Manager(manager.Manager):
return self._set_domain_id_and_mapping(
ref, domain_id, driver, mapping.EntityType.USER)
@notifications.deleted(_USER)
@domains_configured
@exception_translated('user')
def delete_user(self, user_id):
def delete_user(self, user_id, initiator=None):
domain_id, driver, entity_id = (
self._get_domain_driver_and_entity_id(user_id))
# Get user details to invalidate the cache.
@ -707,11 +707,11 @@ class Manager(manager.Manager):
user_old['domain_id'])
self.credential_api.delete_credentials_for_user(user_id)
self.id_mapping_api.delete_id_mapping(user_id)
notifications.Audit.deleted(self._USER, user_id, initiator)
@notifications.created(_GROUP, result_id_arg_attr='id')
@domains_configured
@exception_translated('group')
def create_group(self, group_ref):
def create_group(self, group_ref, initiator=None):
group = group_ref.copy()
group.setdefault('description', '')
domain_id = group['domain_id']
@ -726,6 +726,9 @@ class Manager(manager.Manager):
# that particular driver type.
group['id'] = uuid.uuid4().hex
ref = driver.create_group(group['id'], group)
notifications.Audit.created(self._GROUP, group['id'], initiator)
return self._set_domain_id_and_mapping(
ref, domain_id, driver, mapping.EntityType.GROUP)
@ -748,10 +751,9 @@ class Manager(manager.Manager):
return self._set_domain_id_and_mapping(
ref, domain_id, driver, mapping.EntityType.GROUP)
@notifications.updated(_GROUP)
@domains_configured
@exception_translated('group')
def update_group(self, group_id, group):
def update_group(self, group_id, group, initiator=None):
if 'domain_id' in group:
self.resource_api.get_domain(group['domain_id'])
domain_id, driver, entity_id = (
@ -759,13 +761,13 @@ class Manager(manager.Manager):
group = self._clear_domain_id_if_domain_unaware(driver, group)
ref = driver.update_group(entity_id, group)
self.get_group.invalidate(self, group_id)
notifications.Audit.updated(self._GROUP, group_id, initiator)
return self._set_domain_id_and_mapping(
ref, domain_id, driver, mapping.EntityType.GROUP)
@notifications.deleted(_GROUP)
@domains_configured
@exception_translated('group')
def delete_group(self, group_id):
def delete_group(self, group_id, initiator=None):
domain_id, driver, entity_id = (
self._get_domain_driver_and_entity_id(group_id))
user_ids = (u['id'] for u in self.list_users_in_group(group_id))
@ -773,6 +775,9 @@ class Manager(manager.Manager):
self.get_group.invalidate(self, group_id)
self.id_mapping_api.delete_id_mapping(group_id)
self.assignment_api.delete_group(group_id)
notifications.Audit.deleted(self._GROUP, group_id, initiator)
for uid in user_ids:
self.emit_invalidate_user_token_persistence(uid)

View File

@ -15,6 +15,7 @@
from keystone.common import controller
from keystone.common import dependency
from keystone.common import validation
from keystone import notifications
from keystone.policy import schema
@ -27,8 +28,8 @@ class PolicyV3(controller.V3Controller):
@validation.validated(schema.policy_create, 'policy')
def create_policy(self, context, policy):
ref = self._assign_unique_id(self._normalize_dict(policy))
ref = self.policy_api.create_policy(ref['id'], ref)
initiator = notifications._get_request_audit_info(context)
ref = self.policy_api.create_policy(ref['id'], ref, initiator)
return PolicyV3.wrap_member(context, ref)
@controller.filterprotected('type')
@ -45,9 +46,11 @@ class PolicyV3(controller.V3Controller):
@controller.protected()
@validation.validated(schema.policy_update, 'policy')
def update_policy(self, context, policy_id, policy):
ref = self.policy_api.update_policy(policy_id, policy)
initiator = notifications._get_request_audit_info(context)
ref = self.policy_api.update_policy(policy_id, policy, initiator)
return PolicyV3.wrap_member(context, ref)
@controller.protected()
def delete_policy(self, context, policy_id):
return self.policy_api.delete_policy(policy_id)
initiator = notifications._get_request_audit_info(context)
return self.policy_api.delete_policy(policy_id, initiator)

View File

@ -41,9 +41,10 @@ class Manager(manager.Manager):
def __init__(self):
super(Manager, self).__init__(CONF.policy.driver)
@notifications.created(_POLICY)
def create_policy(self, policy_id, policy):
return self.driver.create_policy(policy_id, policy)
def create_policy(self, policy_id, policy, initiator=None):
ref = self.driver.create_policy(policy_id, policy)
notifications.Audit.created(self._POLICY, policy_id, initiator)
return ref
def get_policy(self, policy_id):
try:
@ -51,14 +52,15 @@ class Manager(manager.Manager):
except exception.NotFound:
raise exception.PolicyNotFound(policy_id=policy_id)
@notifications.updated(_POLICY)
def update_policy(self, policy_id, policy):
def update_policy(self, policy_id, policy, initiator=None):
if 'id' in policy and policy_id != policy['id']:
raise exception.ValidationError('Cannot change policy ID')
try:
return self.driver.update_policy(policy_id, policy)
ref = self.driver.update_policy(policy_id, policy)
except exception.NotFound:
raise exception.PolicyNotFound(policy_id=policy_id)
notifications.Audit.updated(self._POLICY, policy_id, initiator)
return ref
@manager.response_truncated
def list_policies(self, hints=None):
@ -67,12 +69,13 @@ class Manager(manager.Manager):
# caller.
return self.driver.list_policies()
@notifications.deleted(_POLICY)
def delete_policy(self, policy_id):
def delete_policy(self, policy_id, initiator=None):
try:
return self.driver.delete_policy(policy_id)
ret = self.driver.delete_policy(policy_id)
except exception.NotFound:
raise exception.PolicyNotFound(policy_id=policy_id)
notifications.Audit.deleted(self._POLICY, policy_id, initiator)
return ret
@six.add_metaclass(abc.ABCMeta)

View File

@ -25,6 +25,7 @@ from keystone.common import dependency
from keystone.common import validation
from keystone import exception
from keystone.i18n import _
from keystone import notifications
from keystone.resource import schema
@ -114,7 +115,8 @@ class DomainV3(controller.V3Controller):
@validation.validated(schema.domain_create, 'domain')
def create_domain(self, context, domain):
ref = self._assign_unique_id(self._normalize_dict(domain))
ref = self.resource_api.create_domain(ref['id'], ref)
initiator = notifications._get_request_audit_info(context)
ref = self.resource_api.create_domain(ref['id'], ref, initiator)
return DomainV3.wrap_member(context, ref)
@controller.filterprotected('enabled', 'name')
@ -132,12 +134,14 @@ class DomainV3(controller.V3Controller):
@validation.validated(schema.domain_update, 'domain')
def update_domain(self, context, domain_id, domain):
self._require_matching_id(domain_id, domain)
ref = self.resource_api.update_domain(domain_id, domain)
initiator = notifications._get_request_audit_info(context)
ref = self.resource_api.update_domain(domain_id, domain, initiator)
return DomainV3.wrap_member(context, ref)
@controller.protected()
def delete_domain(self, context, domain_id):
return self.resource_api.delete_domain(domain_id)
initiator = notifications._get_request_audit_info(context)
return self.resource_api.delete_domain(domain_id, initiator)
@dependency.requires('resource_api')
@ -154,7 +158,9 @@ class ProjectV3(controller.V3Controller):
def create_project(self, context, project):
ref = self._assign_unique_id(self._normalize_dict(project))
ref = self._normalize_domain_id(context, ref)
ref = self.resource_api.create_project(ref['id'], ref)
initiator = notifications._get_request_audit_info(context)
ref = self.resource_api.create_project(ref['id'], ref,
initiator=initiator)
return ProjectV3.wrap_member(context, ref)
@controller.filterprotected('domain_id', 'enabled', 'name',
@ -220,9 +226,13 @@ class ProjectV3(controller.V3Controller):
self._require_matching_id(project_id, project)
self._require_matching_domain_id(
project_id, project, self.resource_api.get_project)
ref = self.resource_api.update_project(project_id, project)
initiator = notifications._get_request_audit_info(context)
ref = self.resource_api.update_project(project_id, project,
initiator=initiator)
return ProjectV3.wrap_member(context, ref)
@controller.protected()
def delete_project(self, context, project_id):
return self.resource_api.delete_project(project_id)
initiator = notifications._get_request_audit_info(context)
return self.resource_api.delete_project(project_id,
initiator=initiator)

View File

@ -83,8 +83,7 @@ class Manager(manager.Manager):
action=_('max hierarchy depth reached for '
'%s branch.') % project_id)
@notifications.created(_PROJECT)
def create_project(self, tenant_id, tenant):
def create_project(self, tenant_id, tenant, initiator=None):
tenant = tenant.copy()
tenant.setdefault('enabled', True)
tenant['enabled'] = clean.project_enabled(tenant['enabled'])
@ -109,6 +108,7 @@ class Manager(manager.Manager):
parents_list)
ret = self.driver.create_project(tenant_id, tenant)
notifications.Audit.created(self._PROJECT, tenant_id, initiator)
if SHOULD_CACHE(ret):
self.get_project.set(ret, self, tenant_id)
self.get_project_by_name.set(ret, self, ret['name'],
@ -188,8 +188,7 @@ class Manager(manager.Manager):
'its subtree contains enabled '
'projects') % project_id)
@notifications.updated(_PROJECT)
def update_project(self, tenant_id, tenant):
def update_project(self, tenant_id, tenant, initiator=None):
original_tenant = self.driver.get_project(tenant_id)
tenant = tenant.copy()
@ -214,13 +213,13 @@ class Manager(manager.Manager):
self._disable_project(tenant_id)
ret = self.driver.update_project(tenant_id, tenant)
notifications.Audit.updated(self._PROJECT, tenant_id, initiator)
self.get_project.invalidate(self, tenant_id)
self.get_project_by_name.invalidate(self, original_tenant['name'],
original_tenant['domain_id'])
return ret
@notifications.deleted(_PROJECT)
def delete_project(self, tenant_id):
def delete_project(self, tenant_id, initiator=None):
if not self.driver.is_leaf_project(tenant_id):
raise exception.ForbiddenAction(
action=_('cannot delete the project %s since it is not '
@ -238,6 +237,7 @@ class Manager(manager.Manager):
self.get_project_by_name.invalidate(self, project['name'],
project['domain_id'])
self.credential_api.delete_credentials_for_project(tenant_id)
notifications.Audit.deleted(self._PROJECT, tenant_id, initiator)
return ret
def _filter_projects_list(self, projects_list, user_id):
@ -375,8 +375,7 @@ class Manager(manager.Manager):
def get_domain_by_name(self, domain_name):
return self.driver.get_domain_by_name(domain_name)
@notifications.created(_DOMAIN)
def create_domain(self, domain_id, domain):
def create_domain(self, domain_id, domain, initiator=None):
if (not self.identity_api.multiple_domains_supported and
domain_id != CONF.identity.default_domain_id):
raise exception.Forbidden(_('Multiple domains are not supported'))
@ -384,6 +383,9 @@ class Manager(manager.Manager):
domain.setdefault('enabled', True)
domain['enabled'] = clean.domain_enabled(domain['enabled'])
ret = self.driver.create_domain(domain_id, domain)
notifications.Audit.created(self._DOMAIN, domain_id, initiator)
if SHOULD_CACHE(ret):
self.get_domain.set(ret, self, domain_id)
self.get_domain_by_name.set(ret, self, ret['name'])
@ -406,24 +408,25 @@ class Manager(manager.Manager):
"""
pass
@notifications.updated(_DOMAIN)
def update_domain(self, domain_id, domain):
def update_domain(self, domain_id, domain, initiator=None):
self.assert_domain_not_federated(domain_id, domain)
original_domain = self.driver.get_domain(domain_id)
if 'enabled' in domain:
domain['enabled'] = clean.domain_enabled(domain['enabled'])
ret = self.driver.update_domain(domain_id, domain)
notifications.Audit.updated(self._DOMAIN, domain_id, initiator)
# disable owned users & projects when the API user specifically set
# enabled=False
if (original_domain.get('enabled', True) and
not domain.get('enabled', True)):
self._disable_domain(domain_id)
notifications.Audit.disabled(self._DOMAIN, domain_id, initiator,
public=False)
self.get_domain.invalidate(self, domain_id)
self.get_domain_by_name.invalidate(self, original_domain['name'])
return ret
@notifications.deleted(_DOMAIN)
def delete_domain(self, domain_id):
def delete_domain(self, domain_id, initiator=None):
# explicitly forbid deleting the default domain (this should be a
# carefully orchestrated manual process involving configuration
# changes, etc)
@ -451,6 +454,7 @@ class Manager(manager.Manager):
# to the backend to delete all assignments for this domain.
# (see Bug #1277847)
self.driver.delete_domain(domain_id)
notifications.Audit.deleted(self._DOMAIN, domain_id, initiator)
self.get_domain.invalidate(self, domain_id)
self.get_domain_by_name.invalidate(self, domain['name'])

View File

@ -619,6 +619,17 @@ class NotificationsForEntities(test_v3.RestfulTestCase):
# No audit event should have occurred
self.assertEqual(0, len(self._audits))
def test_initiator_data_is_set(self):
ref = self.new_domain_ref()
resp = self.post('/domains', body={'domain': ref})
resource_id = resp.result.get('domain').get('id')
self._assert_last_audit(resource_id, CREATED_OPERATION, 'domain',
cadftaxonomy.SECURITY_DOMAIN)
self.assertTrue(len(self._audits) > 0)
audit = self._audits[-1]
payload = audit['payload']
self.assertEqual(self.user_id, payload['initiator']['id'])
class CADFNotificationsForEntities(NotificationsForEntities):