Exemplo n.º 1
0
    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
Exemplo n.º 2
0
    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
Exemplo n.º 3
0
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
Exemplo n.º 4
0
    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
Exemplo n.º 5
0
 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"
Exemplo n.º 6
0
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)
Exemplo n.º 7
0
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)
Exemplo n.º 8
0
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)
Exemplo n.º 9
0
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)
Exemplo n.º 10
0
    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)
Exemplo n.º 11
0
    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)
Exemplo n.º 12
0
    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)
Exemplo n.º 13
0
    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)
Exemplo n.º 14
0
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
Exemplo n.º 15
0
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