def get_permission_object_id(self, request, object_id=None): """Returns the permission object id for the current request. In the nominal case, it is just the current URI without version prefix. For plural endpoint, it is the related object URI using the specified `object_id`. See :meth:`kinto.core.resource.model.SharableModel` and :meth:`kinto.core.authorization.RouteFactory.__init__` """ object_uri = utils.strip_uri_prefix(request.path) if self.on_plural_endpoint and object_id is not None: # With the current request on a plural endpoint, the object URI must # be found out by inspecting the "plural" service and its sibling # "object" service. (see `register_resource()`) matchdict = {**request.matchdict, "id": object_id} try: object_uri = utils.instance_uri(request, self.resource_name, **matchdict) object_uri = object_uri.replace("%2A", "*") except KeyError: # Maybe the resource has no single object endpoint. # We consider that object URIs in permissions backend will # be stored naively: object_uri = f"{object_uri}/{object_id}" return object_uri
def get_permission_object_id(self, request, object_id=None): """Returns the permission object id for the current request. In the nominal case, it is just the current URI without version prefix. For collections, it is the related record URI using the specified `object_id`. See :meth:`kinto.core.resource.model.SharableModel` and :meth:`kinto.core.authorization.RouteFactory.__init__` """ object_uri = utils.strip_uri_prefix(request.path) if self.on_collection and object_id is not None: # With the current request on a collection, the record URI must # be found out by inspecting the collection service and its sibling # record service. matchdict = request.matchdict.copy() matchdict['id'] = object_id try: object_uri = utils.instance_uri(request, self.resource_name, **matchdict) if object_id == '*': object_uri = object_uri.replace('%2A', '*') except KeyError: # Maybe the resource has no single record endpoint. # We consider that object URIs in permissions backend will # be stored naively: object_uri = object_uri + '/' + object_id return object_uri
def reset_password_flow(username, password, request): cache_key = get_account_cache_key(username, request.registry) hashed_password = utils.hmac_digest(cache_key, password) pwd_str = password.encode(encoding="utf-8") cached_password = get_cached_reset_password(username, request.registry) if not cached_password: return None # The temporary reset password is only available for changing a user's password. if request.method.lower() not in ["post", "put", "patch"]: return None # Only allow modifying a user account, no other resource. uri = utils.strip_uri_prefix(request.path) resource_name, _ = utils.view_lookup(request, uri) if resource_name != "account": return None try: data = request.json["data"] except (ValueError, KeyError): return None # Request one and only one data field: the `password`. if not data or "password" not in data or len(data.keys()) > 1: return None cached_password_str = cached_password.encode(encoding="utf-8") if bcrypt.checkpw(pwd_str, cached_password_str): # Remove the temporary reset password from the cache. delete_cached_reset_password(username, request.registry) cache_account(hashed_password, username, request.registry) return True
def __init__(self, request): super().__init__(request) records_plural = utils.strip_uri_prefix( request.path.replace("/search", "/records") ) self.permission_object_id = records_plural self.required_permission = "read"
def notify_resource_event(request, parent_id, timestamp, data, action, old=None): """ Request helper to stack a resource event. If a similar event (same resource, same action) already occured during the current transaction (e.g. batch) then just extend the impacted records of the previous one. """ if action == ACTIONS.READ: if not isinstance(data, list): data = [data] impacted = data elif action == ACTIONS.CREATE: impacted = [{'new': data}] elif action == ACTIONS.DELETE: if not isinstance(data, list): impacted = [{'new': data, 'old': old}] else: impacted = [] for i, new in enumerate(data): impacted.append({'new': new, 'old': old[i]}) else: # ACTIONS.UPDATE: impacted = [{'new': data, 'old': old}] # Get previously triggered events. events = request.bound_data.setdefault('resource_events', OrderedDict()) resource_name = request.current_resource_name # Group events by resource and action. group_by = '{}-{}-{}'.format(resource_name, parent_id, action.value) if group_by in events: # Add to impacted records of existing event. already_impacted = events[group_by][2] already_impacted.extend(impacted) else: # Create new event. payload = { 'timestamp': timestamp, 'action': action.value, 'uri': strip_uri_prefix(request.path), 'user_id': request.prefixed_userid, 'resource_name': resource_name } matchdict = dict(request.matchdict) if 'id' in request.matchdict: matchdict[resource_name + '_id'] = matchdict.pop('id') payload.update(**matchdict) events[group_by] = (action, payload, impacted, request)
def notify_resource_event( request, parent_id, timestamp, data, action, old=None, resource_name=None, resource_data=None ): """Request helper to stack a resource event. If a similar event (same resource, same action) already occured during the current transaction (e.g. batch) then just extend the impacted records of the previous one. :param resource_name: The name of the resource on which the event happened (taken from the request if not provided). :param resource_data: Information about the resource on which the event is being emitted. Usually contains information about how to find this record in the hierarchy (for instance, ``bucket_id`` and ``collection_id`` for a record). Taken from the request matchdict if absent. :type resource_data: dict """ if action == ACTIONS.READ: if not isinstance(data, list): data = [data] impacted = data elif action == ACTIONS.CREATE: impacted = [{"new": data}] elif action == ACTIONS.DELETE: if not isinstance(data, list): impacted = [{"new": data, "old": old}] else: impacted = [] for i, new in enumerate(data): impacted.append({"new": new, "old": old[i]}) else: # ACTIONS.UPDATE: impacted = [{"new": data, "old": old}] # Get previously triggered events. events = request.bound_data.setdefault("resource_events", EventCollector()) resource_name = resource_name or request.current_resource_name matchdict = resource_data or dict(request.matchdict) payload = { "timestamp": timestamp, "action": action.value, # Deprecated: don't actually use URI (see #945). "uri": strip_uri_prefix(request.path), "user_id": request.prefixed_userid, "resource_name": resource_name, } # Deprecated: don't actually use `resource_name_id` either (see #945). if "id" in request.matchdict: matchdict[resource_name + "_id"] = matchdict.pop("id") payload.update(**matchdict) events.add_event(resource_name, parent_id, action, payload, impacted, request)
def notify_resource_event( request, parent_id, timestamp, data, action, old=None, resource_name=None, resource_data=None ): """Request helper to stack a resource event. If a similar event (same resource, same action) already occured during the current transaction (e.g. batch) then just extend the impacted objects of the previous one. :param resource_name: The name of the resource on which the event happened (taken from the request if not provided). :param resource_data: Information about the resource on which the event is being emitted. Usually contains information about how to find this object in the hierarchy (for instance, ``bucket_id`` and ``collection_id`` for a record). Taken from the request matchdict if absent. :type resource_data: dict """ if action == ACTIONS.READ: if not isinstance(data, list): data = [data] impacted = data elif action == ACTIONS.CREATE: impacted = [{"new": data}] elif action == ACTIONS.DELETE: if not isinstance(data, list): impacted = [{"new": data, "old": old}] else: impacted = [] for i, new in enumerate(data): impacted.append({"new": new, "old": old[i]}) else: # ACTIONS.UPDATE: impacted = [{"new": data, "old": old}] # Get previously triggered events. events = request.bound_data.setdefault("resource_events", EventCollector()) resource_name = resource_name or request.current_resource_name matchdict = resource_data or dict(request.matchdict) payload = { "timestamp": timestamp, "action": action.value, # Deprecated: don't actually use URI (see #945). "uri": strip_uri_prefix(request.path), "user_id": request.prefixed_userid, "resource_name": resource_name, } # Deprecated: don't actually use `resource_name_id` either (see #945). if "id" in request.matchdict: matchdict[resource_name + "_id"] = matchdict.pop("id") payload.update(**matchdict) events.add_event(resource_name, parent_id, action, payload, impacted, request)
def notify_resource_event(request, parent_id, timestamp, data, action, old=None): """ Request helper to stack a resource event. If a similar event (same resource, same action) already occured during the current transaction (e.g. batch) then just extend the impacted records of the previous one. """ if action == ACTIONS.READ: if not isinstance(data, list): data = [data] impacted = data elif action == ACTIONS.CREATE: impacted = [{'new': data}] elif action == ACTIONS.DELETE: if not isinstance(data, list): impacted = [{'new': data, 'old': old}] else: impacted = [] for i, new in enumerate(data): impacted.append({'new': new, 'old': old[i]}) elif action == ACTIONS.UPDATE: impacted = [{'new': data, 'old': old}] # Get previously triggered events. events = request.bound_data.setdefault("resource_events", OrderedDict()) resource_name = request.current_resource_name # Group events by resource and action. group_by = resource_name + parent_id + action.value if group_by in events: # Add to impacted records of existing event. already_impacted = events[group_by][2] already_impacted.extend(impacted) else: # Create new event. payload = {'timestamp': timestamp, 'action': action.value, 'uri': strip_uri_prefix(request.path), 'user_id': request.prefixed_userid, 'resource_name': resource_name} matchdict = dict(request.matchdict) if 'id' in request.matchdict: matchdict[resource_name + '_id'] = matchdict.pop('id') payload.update(**matchdict) events[group_by] = (action, payload, impacted, request)
def __init__(self, action, timestamp, request): self.request = request resource_name = request.current_resource_name self.payload = {'timestamp': timestamp, 'action': action.value, 'uri': strip_uri_prefix(request.path), 'user_id': request.prefixed_userid, 'resource_name': resource_name} matchdict = dict(request.matchdict) if 'id' in request.matchdict: matchdict[resource_name + '_id'] = matchdict.pop('id') self.payload.update(**matchdict)
def get_permission_object_id(self, request, record_id=None): record_uri = request.path if self.on_collection and record_id is not None: # With the current request on a collection, the record URI must # be found out by inspecting the collection service and its sibling # record service. service = request.current_service # XXX: Why not use service.path.format(id=) ? record_service = service.name.replace('-collection', '-record') matchdict = request.matchdict.copy() matchdict['id'] = record_id record_uri = request.route_path(record_service, **matchdict) if record_id == '*': record_uri = record_uri.replace('%2A', '*') return utils.strip_uri_prefix(record_uri)
def __init__(self, action, timestamp, request): self.request = request resource_name = request.current_resource_name self.payload = { 'timestamp': timestamp, 'action': action.value, 'uri': strip_uri_prefix(request.path), 'user_id': request.prefixed_userid, 'resource_name': resource_name } matchdict = dict(request.matchdict) if 'id' in request.matchdict: matchdict[resource_name + '_id'] = matchdict.pop('id') self.payload.update(**matchdict)
def _object_uri(request, resource_name, matchdict, prefix): route_name = '%s-record' % resource_name full = request.route_path(route_name, **matchdict) if not prefix: return core_utils.strip_uri_prefix(full) return full