def test_resource_uuid(self): uuid_str = '536e28c2017e405e89b25a1ed777b952' self.assertEqual(uuid_str, common_utils.resource_uuid(uuid_str)) # Exact 64 length string. uuid_str = ('536e28c2017e405e89b25a1ed777b952' 'f13de678ac714bb1b7d1e9a007c10db5') resource_id_namespace = common_utils.RESOURCE_ID_NAMESPACE transformed_id = uuid.uuid5(resource_id_namespace, uuid_str).hex self.assertEqual(transformed_id, common_utils.resource_uuid(uuid_str)) # Non-ASCII character test. non_ascii_ = 'ß' * 32 transformed_id = uuid.uuid5(resource_id_namespace, non_ascii_).hex self.assertEqual(transformed_id, common_utils.resource_uuid(non_ascii_)) # This input is invalid because it's length is more than 64. invalid_input = 'x' * 65 self.assertRaises(ValueError, common_utils.resource_uuid, invalid_input) # 64 length unicode string, to mimic what is returned from mapping_id # backend. uuid_str = six.text_type('536e28c2017e405e89b25a1ed777b952' 'f13de678ac714bb1b7d1e9a007c10db5') resource_id_namespace = common_utils.RESOURCE_ID_NAMESPACE if six.PY2: uuid_str = uuid_str.encode('utf-8') transformed_id = uuid.uuid5(resource_id_namespace, uuid_str).hex self.assertEqual(transformed_id, common_utils.resource_uuid(uuid_str))
def test_resource_non_ascii_chars(self): # IDs with non-ASCII characters will be UUID5 namespaced value = u'ß' * 32 if six.PY2: value = value.encode('utf-8') expected_id = uuid.uuid5(common_utils.RESOURCE_ID_NAMESPACE, value).hex self.assertEqual(expected_id, common_utils.resource_uuid(value))
def wrapper(wrapped_self, user_id, *args, **kwargs): """Will always send a notification.""" target = resource.Resource(typeURI=taxonomy.ACCOUNT_USER) initiator = build_audit_initiator() initiator.user_id = user_id initiator.id = utils.resource_uuid(user_id) try: result = f(wrapped_self, user_id, *args, **kwargs) except (exception.AccountLocked, exception.PasswordExpired) as ex: # Send a CADF event with a reason for PCI-DSS related # authentication failures audit_reason = reason.Reason(str(ex), str(ex.code)) _send_audit_notification(self.action, initiator, taxonomy.OUTCOME_FAILURE, target, self.event_type, reason=audit_reason) raise except Exception: # For authentication failure send a CADF event as well _send_audit_notification(self.action, initiator, taxonomy.OUTCOME_FAILURE, target, self.event_type) raise else: _send_audit_notification(self.action, initiator, taxonomy.OUTCOME_SUCCESS, target, self.event_type) return result
def test_resource_64_char_uuid(self): # Exact 64 length string, like ones used by mapping_id backend, are not # valid UUIDs, so they will be UUID5 namespaced value = u'f13de678ac714bb1b7d1e9a007c10db5' * 2 if six.PY2: value = value.encode('utf-8') expected_id = uuid.uuid5(common_utils.RESOURCE_ID_NAMESPACE, value).hex self.assertEqual(expected_id, common_utils.resource_uuid(value))
def test_resource_uuid(self): uuid_str = '536e28c2017e405e89b25a1ed777b952' self.assertEqual(uuid_str, common_utils.resource_uuid(uuid_str)) # Exact 64 length string. uuid_str = ('536e28c2017e405e89b25a1ed777b952' 'f13de678ac714bb1b7d1e9a007c10db5') resource_id_namespace = common_utils.RESOURCE_ID_NAMESPACE transformed_id = uuid.uuid5(resource_id_namespace, uuid_str).hex self.assertEqual(transformed_id, common_utils.resource_uuid(uuid_str)) # Non-ASCII character test. non_ascii_ = 'ß' * 32 transformed_id = uuid.uuid5(resource_id_namespace, non_ascii_).hex self.assertEqual(transformed_id, common_utils.resource_uuid(non_ascii_)) # This input is invalid because it's length is more than 64. invalid_input = 'x' * 65 self.assertRaises(ValueError, common_utils.resource_uuid, invalid_input)
def audit_initiator(self): """A pyCADF initiator describing the current authenticated context.""" pycadf_host = host.Host(address=self.remote_addr, agent=self.user_agent) initiator = resource.Resource(typeURI=taxonomy.ACCOUNT_USER, host=pycadf_host) if self.context.user_id: initiator.id = utils.resource_uuid(self.context.user_id) initiator.user_id = self.context.user_id if self.context.project_id: initiator.project_id = self.context.project_id if self.context.domain_id: initiator.domain_id = self.context.domain_id return initiator
def build_audit_initiator(): """A pyCADF initiator describing the current authenticated context.""" pycadf_host = host.Host(address=flask.request.remote_addr, agent=str(flask.request.user_agent)) initiator = resource.Resource(typeURI=taxonomy.ACCOUNT_USER, host=pycadf_host) oslo_context = flask.request.environ.get(context.REQUEST_CONTEXT_ENV) if oslo_context.user_id: initiator.id = utils.resource_uuid(oslo_context.user_id) initiator.user_id = oslo_context.user_id if oslo_context.project_id: initiator.project_id = oslo_context.project_id if oslo_context.domain_id: initiator.domain_id = oslo_context.domain_id return initiator
def _get_request_audit_info(context, user_id=None): """Collect audit information about the request used for CADF. :param context: Request context :param user_id: Optional user ID, alternatively collected from context :returns: Auditing data about the request :rtype: :class:`pycadf.Resource` """ remote_addr = None http_user_agent = None project_id = None domain_id = None if context and 'environment' in context and context['environment']: environment = context['environment'] remote_addr = environment.get('REMOTE_ADDR') http_user_agent = environment.get('HTTP_USER_AGENT') if not user_id: user_id = environment.get('KEYSTONE_AUTH_CONTEXT', {}).get('user_id') project_id = environment.get('KEYSTONE_AUTH_CONTEXT', {}).get('project_id') domain_id = environment.get('KEYSTONE_AUTH_CONTEXT', {}).get('domain_id') host = pycadf.host.Host(address=remote_addr, agent=http_user_agent) initiator = resource.Resource(typeURI=taxonomy.ACCOUNT_USER, host=host) if user_id: initiator.user_id = user_id initiator.id = utils.resource_uuid(user_id) initiator = _add_username_to_initiator(initiator) if project_id: initiator.project_id = project_id if domain_id: initiator.domain_id = domain_id return initiator
def _get_request_audit_info(context, user_id=None): """Collect audit information about the request used for CADF. :param context: Request context :param user_id: Optional user ID, alternatively collected from context :returns: Auditing data about the request :rtype: :class:`pycadf.Resource` """ remote_addr = None http_user_agent = None project_id = None domain_id = None if context and 'environment' in context and context['environment']: environment = context['environment'] remote_addr = environment.get('REMOTE_ADDR') http_user_agent = environment.get('HTTP_USER_AGENT') if not user_id: user_id = environment.get('KEYSTONE_AUTH_CONTEXT', {}).get('user_id') project_id = environment.get('KEYSTONE_AUTH_CONTEXT', {}).get('project_id') domain_id = environment.get('KEYSTONE_AUTH_CONTEXT', {}).get('domain_id') host = pycadf.host.Host(address=remote_addr, agent=http_user_agent) initiator = resource.Resource(typeURI=taxonomy.ACCOUNT_USER, host=host) if user_id: initiator.user_id = user_id initiator.id = utils.resource_uuid(user_id) if project_id: initiator.project_id = project_id if domain_id: initiator.domain_id = domain_id return initiator
def build_audit_initiator(): """A pyCADF initiator describing the current authenticated context.""" pycadf_host = host.Host(address=flask.request.remote_addr, agent=str(flask.request.user_agent)) initiator = resource.Resource(typeURI=taxonomy.ACCOUNT_USER, host=pycadf_host) oslo_context = flask.request.environ.get(context.REQUEST_CONTEXT_ENV) if oslo_context.user_id: initiator.id = utils.resource_uuid(oslo_context.user_id) initiator.user_id = oslo_context.user_id if oslo_context.project_id: initiator.project_id = oslo_context.project_id if oslo_context.domain_id: initiator.domain_id = oslo_context.domain_id initiator.request_id = oslo_context.request_id if oslo_context.global_request_id: initiator.global_request_id = oslo_context.global_request_id return initiator
def test_resource_uuid(self): # Basic uuid test, most IDs issued by keystone look like this: value = u'536e28c2017e405e89b25a1ed777b952' self.assertEqual(value, common_utils.resource_uuid(value))