Exemplo n.º 1
0
    def __acl__(self):
        """Return ACL for bulk end-points."""

        if authority := client_authority(self.request):
            # Currently only LMS uses this end-point
            if authority.startswith("lms.") and authority.endswith(
                    ".hypothes.is"):
                return [(Allow, f"client_authority:{authority}", "bulk_action")
                        ]
Exemplo n.º 2
0
def create(request):
    """Create a group from the POST payload."""
    appstruct = CreateGroupAPISchema(
        default_authority=request.default_authority,
        group_authority=client_authority(request)
        or request.default_authority).validate(_json_payload(request))

    group_service = request.find_service(name='group')
    group_create_service = request.find_service(name='group_create')

    # Check for duplicate group
    groupid = appstruct.get('groupid', None)
    if groupid is not None:
        duplicate_group = group_service.fetch(pubid_or_groupid=groupid)
        if duplicate_group:
            raise ConflictError(
                _("group with groupid '{}' already exists").format(groupid))

    group = group_create_service.create_private_group(
        name=appstruct['name'],
        userid=request.user.userid,
        description=appstruct.get('description', None),
        groupid=groupid,
    )
    return GroupJSONPresenter(GroupContext(
        group, request)).asdict(expand=['organization'])
Exemplo n.º 3
0
def create(request):
    """Create a group from the POST payload."""
    appstruct = CreateGroupAPISchema(
        default_authority=request.default_authority,
        group_authority=client_authority(request) or request.default_authority,
    ).validate(_json_payload(request))

    group_service = request.find_service(name="group")
    group_create_service = request.find_service(name="group_create")

    # Check for duplicate group
    groupid = appstruct.get("groupid", None)
    if groupid is not None:
        duplicate_group = group_service.fetch(pubid_or_groupid=groupid)
        if duplicate_group:
            raise HTTPConflict(
                _("group with groupid '{}' already exists").format(groupid))

    group = group_create_service.create_private_group(
        name=appstruct["name"],
        userid=request.user.userid,
        description=appstruct.get("description", None),
        groupid=groupid,
    )
    return GroupJSONPresenter(
        group, request).asdict(expand=["organization", "scopes"])
Exemplo n.º 4
0
def create(request):
    """Create a group from the POST payload."""
    appstruct = CreateGroupAPISchema(
        default_authority=request.default_authority,
        group_authority=client_authority(request) or request.default_authority,
    ).validate(_json_payload(request))

    group_service = request.find_service(name="group")
    group_create_service = request.find_service(name="group_create")

    # Check for duplicate group
    groupid = appstruct.get("groupid", None)
    if groupid is not None:
        duplicate_group = group_service.fetch(pubid_or_groupid=groupid)
        if duplicate_group:
            raise HTTPConflict(
                _("group with groupid '{}' already exists").format(groupid)
            )

    group = group_create_service.create_private_group(
        name=appstruct["name"],
        userid=request.user.userid,
        description=appstruct.get("description", None),
        groupid=groupid,
    )
    return GroupJSONPresenter(GroupContext(group, request)).asdict(
        expand=["organization", "scopes"]
    )
Exemplo n.º 5
0
    def __getitem__(self, username):
        authority = client_authority(self.request) or self.request.default_authority
        user = self.user_svc.fetch(username, authority)

        if not user:
            raise KeyError()

        return user
Exemplo n.º 6
0
Arquivo: roots.py Projeto: kael/h
    def __getitem__(self, username):
        authority = client_authority(self.request) or self.request.default_authority
        user = self.user_svc.fetch(username, authority)

        if not user:
            raise KeyError()

        return user
Exemplo n.º 7
0
def upsert(context, request):
    """
    Create or update a group from a PUT payload.

    If no group model is present in the passed ``context`` (on ``context.group``),
    treat this as a create action and delegate to ``create``.

    Otherwise, replace the existing group's resource properties entirely and update
    the object.

    :arg context:
    :type context: h.traversal.GroupUpsertContext
    """
    if context.group is None:
        return create(request)

    group = context.group

    # Because this is a PUT endpoint and not a PATCH, a full replacement of the
    # entire resource is expected. Thus, we're validating against the Create schema
    # here as we want to make sure properties required for a fresh object are present
    appstruct = CreateGroupAPISchema(
        default_authority=request.default_authority,
        group_authority=client_authority(request) or request.default_authority,
    ).validate(_json_payload(request))

    group_update_service = request.find_service(name="group_update")
    group_service = request.find_service(name="group")

    # Check for duplicate group
    groupid = appstruct.get("groupid", None)
    if groupid is not None:
        duplicate_group = group_service.fetch(pubid_or_groupid=groupid)
        if duplicate_group and (duplicate_group != group):
            raise HTTPConflict(
                _("group with groupid '{}' already exists").format(groupid)
            )

    # Need to make sure every resource-defined property is present, as this
    # is meant as a full-resource-replace operation.
    # TODO: This may be better handled in the schema at some point
    update_properties = {
        "name": appstruct["name"],
        "description": appstruct.get("description", ""),
        "groupid": appstruct.get("groupid", None),
    }

    group = group_update_service.update(group, **update_properties)

    # Note that this view takes a ``GroupUpsertContext`` but uses a ``GroupContext`` here
    return GroupJSONPresenter(GroupContext(group, request)).asdict(
        expand=["organization", "scopes"]
    )
Exemplo n.º 8
0
def upsert(context, request):
    """
    Create or update a group from a PUT payload.

    If no group model is present in the passed ``context`` (on ``context.group``),
    treat this as a create action and delegate to ``create``.

    Otherwise, replace the existing group's resource properties entirely and update
    the object.

    :arg context:
    :type context: h.traversal.GroupUpsertContext
    """
    if context.group is None:
        return create(request)

    group = context.group

    # Because this is a PUT endpoint and not a PATCH, a full replacement of the
    # entire resource is expected. Thus, we're validating against the Create schema
    # here as we want to make sure properties required for a fresh object are present
    appstruct = CreateGroupAPISchema(
        default_authority=request.default_authority,
        group_authority=client_authority(request) or request.default_authority,
    ).validate(_json_payload(request))

    group_update_service = request.find_service(name="group_update")
    group_service = request.find_service(name="group")

    # Check for duplicate group
    groupid = appstruct.get("groupid", None)
    if groupid is not None:
        duplicate_group = group_service.fetch(pubid_or_groupid=groupid)
        if duplicate_group and (duplicate_group != group):
            raise HTTPConflict(
                _("group with groupid '{}' already exists").format(groupid)
            )

    # Need to make sure every resource-defined property is present, as this
    # is meant as a full-resource-replace operation.
    # TODO: This may be better handled in the schema at some point
    update_properties = {
        "name": appstruct["name"],
        "description": appstruct.get("description", ""),
        "groupid": appstruct.get("groupid", None),
    }

    group = group_update_service.update(group, **update_properties)

    # Note that this view takes a ``GroupUpsertContext`` but uses a ``GroupContext`` here
    return GroupJSONPresenter(GroupContext(group, request)).asdict(
        expand=["organization", "scopes"]
    )
Exemplo n.º 9
0
def create(request):
    """
    Create a user.

    This API endpoint allows authorised clients (those able to provide a valid
    Client ID and Client Secret) to create users in their authority. These
    users are created pre-activated, and are unable to log in to the web
    service directly.

    Note: the authority-enforcement logic herein is, by necessity, strange.
    The API accepts an ``authority`` parameter but the only valid value for
    the param is the client's verified authority. If the param does not
    match the client's authority, ``ValidationError`` is raised.

    :raises ValidationError: if ``authority`` param does not match client
                             authority
    :raises HTTPConflict:    if user already exists
    """
    client_authority_ = client_authority(request)
    schema = CreateUserAPISchema()
    appstruct = schema.validate(_json_payload(request))

    # Enforce authority match
    if appstruct["authority"] != client_authority_:
        raise ValidationError(
            "authority '{auth_param}' does not match client authority".format(
                auth_param=appstruct["authority"]
            )
        )

    user_unique_service = request.find_service(name="user_unique")

    try:
        user_unique_service.ensure_unique(appstruct, authority=client_authority_)
    except DuplicateUserError as err:
        raise HTTPConflict(str(err))

    user_signup_service = request.find_service(name="user_signup")
    user = user_signup_service.signup(require_activation=False, **appstruct)
    presenter = UserJSONPresenter(user)
    return presenter.asdict()
Exemplo n.º 10
0
def create(request):
    """
    Create a user.

    This API endpoint allows authorised clients (those able to provide a valid
    Client ID and Client Secret) to create users in their authority. These
    users are created pre-activated, and are unable to log in to the web
    service directly.

    Note: the authority-enforcement logic herein is, by necessity, strange.
    The API accepts an ``authority`` parameter but the only valid value for
    the param is the client's verified authority. If the param does not
    match the client's authority, ``ValidationError`` is raised.

    :raises ValidationError: if ``authority`` param does not match client
                             authority
    :raises HTTPConflict:    if user already exists
    """
    client_authority_ = client_authority(request)
    schema = CreateUserAPISchema()
    appstruct = schema.validate(_json_payload(request))

    # Enforce authority match
    if appstruct["authority"] != client_authority_:
        raise ValidationError(
            "authority '{auth_param}' does not match client authority".format(
                auth_param=appstruct["authority"]
            )
        )

    user_unique_service = request.find_service(name="user_unique")

    try:
        user_unique_service.ensure_unique(appstruct, authority=client_authority_)
    except DuplicateUserError as err:
        raise HTTPConflict(str(err))

    user_signup_service = request.find_service(name="user_signup")
    user = user_signup_service.signup(require_activation=False, **appstruct)
    presenter = UserJSONPresenter(user)
    return presenter.asdict()
Exemplo n.º 11
0
def bulk(request):
    """
    Perform a bulk request which can modify multiple records in on go.

    This end-point can:

     * Upsert users
     * Upsert groups
     * Add users to groups

    This end-point is intended to be called using the classes provided by
    `h_api.bulk_api`.
    """

    results = BulkAPI.from_byte_stream(
        request.body_file,
        executor=BulkExecutor(db=request.db,
                              authority=client_authority(request)),
    )

    if results is None:
        return Response(status=204)

    # When we get an iterator we must force the first return value to be
    # created to be sure input validation has occurred. Otherwise we might
    # raise errors outside of the view when called

    try:
        results = chain(  # pylint: disable=redefined-variable-type
            [next(results)], results)
    except StopIteration:
        results = []

    # An NDJSON response is required
    return Response(
        app_iter=((json.dumps(result) + "\n").encode("utf-8")
                  for result in results),
        status=200,
        content_type="application/x-ndjson",
    )
Exemplo n.º 12
0
def update(group, request):
    """Update a group from a PATCH payload."""
    appstruct = UpdateGroupAPISchema(
        default_authority=request.default_authority,
        group_authority=client_authority(request) or request.default_authority,
    ).validate(_json_payload(request))

    group_update_service = request.find_service(name="group_update")
    group_service = request.find_service(name="group")

    # Check for duplicate group
    groupid = appstruct.get("groupid", None)
    if groupid is not None:
        duplicate_group = group_service.fetch(pubid_or_groupid=groupid)
        if duplicate_group and (duplicate_group != group):
            raise HTTPConflict(
                _("group with groupid '{}' already exists").format(groupid))

    group = group_update_service.update(group, **appstruct)

    return GroupJSONPresenter(GroupContext(
        group, request)).asdict(expand=["organization", "scopes"])
Exemplo n.º 13
0
def update(group, request):
    """Update a group from a PATCH payload."""
    appstruct = UpdateGroupAPISchema(
        default_authority=request.default_authority,
        group_authority=client_authority(request) or request.default_authority,
    ).validate(_json_payload(request))

    group_update_service = request.find_service(name="group_update")
    group_service = request.find_service(name="group")

    # Check for duplicate group
    groupid = appstruct.get("groupid", None)
    if groupid is not None:
        duplicate_group = group_service.fetch(pubid_or_groupid=groupid)
        if duplicate_group and (duplicate_group != group):
            raise HTTPConflict(
                _("group with groupid '{}' already exists").format(groupid)
            )

    group = group_update_service.update(group, **appstruct)

    return GroupJSONPresenter(GroupContext(group, request)).asdict(
        expand=["organization", "scopes"]
    )
Exemplo n.º 14
0
    def test_it_returns_authority_if_authority_principal_matchpyramid_requesi(
        self, principals, authority, pyramid_request, pyramid_config
    ):
        pyramid_config.testing_securitypolicy("LYZADOODLE", groupids=principals)

        assert util.client_authority(pyramid_request) == authority
Exemplo n.º 15
0
    def test_it_returns_authority_if_authority_principal_matchpyramid_requesi(
        self, principals, authority, pyramid_request, pyramid_config
    ):
        pyramid_config.testing_securitypolicy("LYZADOODLE", groupids=principals)

        assert util.client_authority(pyramid_request) == authority