def delete_resource(request):
    resource = ar.get_resource_matchdict_checked(request)
    service_push = asbool(
        ar.get_multiformat_body(request, "service_push", default=False))
    res_content = {"resource": format_resource(resource, basic_info=True)}
    ax.evaluate_call(
        lambda: models.RESOURCE_TREE_SERVICE.delete_branch(
            resource_id=resource.resource_id, db_session=request.db),
        fallback=lambda: request.db.rollback(),
        http_error=HTTPForbidden,
        msg_on_fail="Delete resource branch from tree service failed.",
        content=res_content)

    def remove_service_magpie_and_phoenix(res, svc_push, db):
        if res.resource_type != "service":
            svc_push = False
        db.delete(res)
        if svc_push:
            sync_services_phoenix(db.query(models.Service))

    ax.evaluate_call(
        lambda: remove_service_magpie_and_phoenix(resource, service_push,
                                                  request.db),
        fallback=lambda: request.db.rollback(),
        http_error=HTTPForbidden,
        msg_on_fail=s.Resource_DELETE_ForbiddenResponseSchema.description,
        content=res_content)
    return ax.valid_http(http_success=HTTPOk,
                         detail=s.Resource_DELETE_OkResponseSchema.description)
Exemple #2
0
def unregister_service_view(request):
    """
    Unregister a service.
    """
    service = ar.get_service_matchdict_checked(request)
    service_push = asbool(
        ar.get_multiformat_delete(request, "service_push", default=False))
    svc_content = sf.format_service(service, show_private_url=True)
    svc_res_id = service.resource_id
    ax.evaluate_call(lambda: models.resource_tree_service.delete_branch(
        resource_id=svc_res_id, db_session=request.db),
                     fallback=lambda: request.db.rollback(),
                     httpError=HTTPForbidden,
                     msgOnFail="Delete service from resource tree failed.",
                     content=svc_content)

    def remove_service_magpie_and_phoenix(svc, svc_push, db_session):
        db_session.delete(svc)
        if svc_push and svc.type in SERVICES_PHOENIX_ALLOWED:
            sync_services_phoenix(db_session.query(models.Service))

    ax.evaluate_call(
        lambda: remove_service_magpie_and_phoenix(service, service_push,
                                                  request.db),
        fallback=lambda: request.db.rollback(),
        httpError=HTTPForbidden,
        msgOnFail=s.Service_DELETE_ForbiddenResponseSchema.description,
        content=svc_content)
    return ax.valid_http(httpSuccess=HTTPOk,
                         detail=s.Service_DELETE_OkResponseSchema.description)
Exemple #3
0
def delete_user_group_view(request):
    """
    Remove a user from a group.
    """
    db = request.db
    user = ar.get_user_matchdict_checked_or_logged(request)
    group = ar.get_group_matchdict_checked(request)

    def del_usr_grp(usr, grp):
        db.query(models.UserGroup) \
            .filter(models.UserGroup.user_id == usr.id) \
            .filter(models.UserGroup.group_id == grp.id) \
            .delete()

    ax.evaluate_call(
        lambda: del_usr_grp(user, group),
        fallback=lambda: db.rollback(),
        httpError=HTTPNotFound,
        msgOnFail=s.UserGroup_DELETE_NotFoundResponseSchema.description,
        content={
            u"user_name": user.user_name,
            u"group_name": group.group_name
        })
    return ax.valid_http(
        httpSuccess=HTTPOk,
        detail=s.UserGroup_DELETE_OkResponseSchema.description)
Exemple #4
0
def resource_factory(**kwargs):
    resource_type = evaluate_call(lambda: kwargs["resource_type"], httpError=HTTPInternalServerError,
                                  msgOnFail="kwargs do not contain required 'resource_type'",
                                  content={u"kwargs": repr(kwargs)})
    return evaluate_call(lambda: RESOURCE_TYPE_DICT[resource_type](**kwargs), httpError=HTTPInternalServerError,
                         msgOnFail="kwargs unpacking failed from specified 'resource_type' and 'RESOURCE_TYPE_DICT'",
                         content={u"kwargs": repr(kwargs), u"RESOURCE_TYPE_DICT": repr(RESOURCE_TYPE_DICT)})
Exemple #5
0
def delete_user_resource_permission_response(user, resource, permission,
                                             db_session):
    # type: (models.User, ServiceOrResourceType, Permission, Session) -> HTTPException
    """
    Get validated response on deleted user resource permission.

    :returns: valid HTTP response on successful operations.
    :raises HTTPException: error HTTP response of corresponding situation.
    """
    check_valid_service_or_resource_permission(permission.value, resource,
                                               db_session)
    resource_id = resource.resource_id
    del_perm = UserResourcePermissionService.get(user.id, resource_id,
                                                 permission.value, db_session)
    ax.evaluate_call(
        lambda: db_session.delete(del_perm),
        fallback=lambda: db_session.rollback(),
        httpError=HTTPNotFound,
        msgOnFail=s.UserResourcePermissions_DELETE_NotFoundResponseSchema.
        description,
        content={
            u"resource_id": resource_id,
            u"user_id": user.id,
            u"permission_name": permission.value
        })
    return ax.valid_http(
        httpSuccess=HTTPOk,
        detail=s.UserResourcePermissions_DELETE_OkResponseSchema.description)
Exemple #6
0
def create_group_resource_permission_response(group, resource, permission, db_session):
    # type: (models.Group, ServiceOrResourceType, Permission, Session) -> HTTPException
    """
    Creates a permission on a group/resource combination if it is permitted and not conflicting.

    :returns: valid HTTP response on successful operations.
    :raises HTTPException: error HTTP response of corresponding situation.
    """
    resource_id = resource.resource_id
    check_valid_service_or_resource_permission(permission.value, resource, db_session)
    perm_content = {u"permission_name": str(permission.value),
                    u"resource": format_resource(resource, basic_info=True),
                    u"group": format_group(group, basic_info=True)}
    existing_perm = ax.evaluate_call(
        lambda: GroupResourcePermissionService.get(group.id, resource_id, permission.value, db_session=db_session),
        fallback=lambda: db_session.rollback(), httpError=HTTPForbidden,
        msgOnFail=s.GroupResourcePermissions_POST_ForbiddenGetResponseSchema.description, content=perm_content
    )
    ax.verify_param(existing_perm, isNone=True, httpError=HTTPConflict,
                    msgOnFail=s.GroupResourcePermissions_POST_ConflictResponseSchema.description, content=perm_content)
    # noinspection PyArgumentList
    new_perm = ax.evaluate_call(
        lambda: models.GroupResourcePermission(resource_id=resource_id, group_id=group.id, perm_name=permission.value),
        fallback=lambda: db_session.rollback(), httpError=HTTPForbidden, content=perm_content,
        msgOnFail=s.GroupResourcePermissions_POST_ForbiddenCreateResponseSchema.description)
    ax.evaluate_call(lambda: db_session.add(new_perm), fallback=lambda: db_session.rollback(),
                     httpError=HTTPForbidden, content=perm_content,
                     msgOnFail=s.GroupResourcePermissions_POST_ForbiddenAddResponseSchema.description)
    return ax.valid_http(httpSuccess=HTTPCreated, content=perm_content,
                         detail=s.GroupResourcePermissions_POST_CreatedResponseSchema.description)
Exemple #7
0
def service_factory(service, request):
    # type: (models.Service, Request) -> ServiceInterface
    """
    Retrieve the specific service class from the provided database service entry.
    """
    ax.verify_param(service,
                    param_compare=models.Service,
                    is_type=True,
                    http_error=HTTPBadRequest,
                    content={"service": repr(service)},
                    msg_on_fail="Cannot process invalid service object")
    service_type = ax.evaluate_call(
        lambda: service.type,
        http_error=HTTPInternalServerError,
        msg_on_fail="Cannot retrieve service type from object")
    ax.verify_param(
        service_type,
        is_in=True,
        param_compare=SERVICE_TYPE_DICT.keys(),
        http_error=HTTPNotImplemented,
        content={"service_type": service_type},
        msg_on_fail="Undefined service type mapping to service object")
    return ax.evaluate_call(
        lambda: SERVICE_TYPE_DICT[service_type](service, request),
        http_error=HTTPInternalServerError,
        msg_on_fail="Failed to find requested service type.")
Exemple #8
0
def delete_user_resource_permission_response(user, resource, permission, db_session, similar=True):
    # type: (models.User, ServiceOrResourceType, PermissionSet, Session, bool) -> HTTPException
    """
    Get validated response on deleted user resource permission.

    :param user: user for which to delete the permission.
    :param resource: service or resource for which to delete the permission.
    :param permission: permission with modifiers to be deleted.
    :param db_session: database connection.
    :param similar:
        Allow matching provided permission against any similar database permission. Otherwise, must match exactly.
    :returns: valid HTTP response on successful operations.
    :raises HTTPException: error HTTP response of corresponding situation.
    """
    ru.check_valid_service_or_resource_permission(permission.name, resource, db_session)
    res_id = resource.resource_id
    if similar:
        found_perm = get_similar_user_resource_permission(user, resource, permission, db_session)
    else:
        found_perm = permission
    del_perm = UserResourcePermissionService.get(user.id, res_id, str(found_perm), db_session)
    permission.type = PermissionType.APPLIED
    err_content = {"resource_id": res_id, "user_id": user.id,
                   "permission_name": str(permission), "permission": permission.json()}
    ax.verify_param(del_perm, not_none=True, http_error=HTTPNotFound, content=err_content,
                    msg_on_fail=s.UserResourcePermissionName_DELETE_NotFoundResponseSchema.description)
    ax.evaluate_call(lambda: db_session.delete(del_perm), fallback=lambda: db_session.rollback(),
                     http_error=HTTPNotFound, content=err_content,
                     msg_on_fail=s.UserResourcePermissionName_DELETE_NotFoundResponseSchema.description)
    return ax.valid_http(http_success=HTTPOk, detail=s.UserResourcePermissionName_DELETE_OkResponseSchema.description)
Exemple #9
0
def create_user_resource_permission_response(user, resource, permission,
                                             db_session):
    # type: (models.User, ServiceOrResourceType, Permission, Session) -> HTTPException
    """
    Creates a permission on a user/resource combination if it is permitted and not conflicting.

    :returns: valid HTTP response on successful operation.
    """
    check_valid_service_or_resource_permission(permission.value, resource,
                                               db_session)
    resource_id = resource.resource_id
    existing_perm = UserResourcePermissionService.by_resource_user_and_perm(
        user_id=user.id,
        resource_id=resource_id,
        perm_name=permission.value,
        db_session=db_session)
    ax.verify_param(
        existing_perm,
        isNone=True,
        httpError=HTTPConflict,
        content={
            u"resource_id": resource_id,
            u"user_id": user.id,
            u"permission_name": permission.value
        },
        msgOnFail=s.UserResourcePermissions_POST_ConflictResponseSchema.
        description)

    # noinspection PyArgumentList
    new_perm = models.UserResourcePermission(resource_id=resource_id,
                                             user_id=user.id,
                                             perm_name=permission.value)
    usr_res_data = {
        u"resource_id": resource_id,
        u"user_id": user.id,
        u"permission_name": permission.value
    }
    ax.verify_param(
        new_perm,
        notNone=True,
        httpError=HTTPForbidden,
        content={
            u"resource_id": resource_id,
            u"user_id": user.id
        },
        msgOnFail=s.UserResourcePermissions_POST_ForbiddenResponseSchema.
        description)
    ax.evaluate_call(
        lambda: db_session.add(new_perm),
        fallback=lambda: db_session.rollback(),
        httpError=HTTPForbidden,
        content=usr_res_data,
        msgOnFail=s.UserResourcePermissions_POST_ForbiddenResponseSchema.
        description)
    return ax.valid_http(
        httpSuccess=HTTPCreated,
        content=usr_res_data,
        detail=s.UserResourcePermissions_POST_CreatedResponseSchema.description
    )
Exemple #10
0
 def _add_to_group(usr, grp):
     # type: (models.User, models.Group) -> None
     # noinspection PyArgumentList
     group_entry = models.UserGroup(group_id=grp.id, user_id=usr.id)
     ax.evaluate_call(
         lambda: db_session.add(group_entry),
         fallback=lambda: db_session.rollback(),
         httpError=HTTPForbidden,
         msgOnFail=s.UserGroup_GET_ForbiddenResponseSchema.description)
Exemple #11
0
def update_service_view(request):
    """
    Update service information.
    """
    service = ar.get_service_matchdict_checked(request)
    service_push = asbool(ar.get_multiformat_body(request, "service_push", default=False))

    def select_update(new_value, old_value):
        return new_value if new_value is not None and not new_value == "" else old_value

    # None/Empty values are accepted in case of unspecified
    svc_name = select_update(ar.get_multiformat_body(request, "service_name"), service.resource_name)
    svc_url = select_update(ar.get_multiformat_body(request, "service_url"), service.url)
    ax.verify_param(svc_name, param_compare="types", not_equal=True,
                    param_name="service_name", http_error=HTTPForbidden,
                    msg_on_fail=s.Service_PATCH_ForbiddenResponseSchema_ReservedKeyword.description)
    ax.verify_param(svc_name == service.resource_name and svc_url == service.url, not_equal=True,
                    param_compare=True, param_name="service_name/service_url",
                    http_error=HTTPBadRequest, msg_on_fail=s.Service_PATCH_BadRequestResponseSchema.description)

    # config explicitly provided as None (null) means override (erase)
    # to leave it as is, just don't specific the field
    old_svc_config = service.configuration
    new_svc_config = ar.get_multiformat_body(request, "configuration")
    if old_svc_config != new_svc_config:
        if new_svc_config is not None:
            ax.verify_param(new_svc_config, param_compare=dict, is_type=True, http_error=HTTPUnprocessableEntity,
                            msg_on_fail=s.Service_CheckConfig_UnprocessableEntityResponseSchema.description)
        service.configuration = new_svc_config

    if svc_name != service.resource_name:
        all_services = request.db.query(models.Service)
        all_svc_names = [svc.resource_name for svc in all_services]
        ax.verify_param(svc_name, not_in=True, param_compare=all_svc_names, with_param=False,
                        http_error=HTTPConflict, content={"service_name": str(svc_name)},
                        msg_on_fail=s.Service_PATCH_ConflictResponseSchema.description)

    def update_service_magpie_and_phoenix(_svc, new_name, new_url, svc_push, db_session):
        _svc.resource_name = new_name
        _svc.url = new_url
        has_getcap = Permission.GET_CAPABILITIES in SERVICE_TYPE_DICT[_svc.type].permissions
        if svc_push and _svc.type in SERVICES_PHOENIX_ALLOWED and has_getcap:
            # (re)apply getcapabilities to updated service to ensure updated push
            su.add_service_getcapabilities_perms(_svc, db_session)
            sync_services_phoenix(db_session.query(models.Service))  # push all services

    old_svc_content = sf.format_service(service, show_private_url=True)
    err_svc_content = {"service": old_svc_content, "new_service_name": svc_name, "new_service_url": svc_url}
    ax.evaluate_call(lambda: update_service_magpie_and_phoenix(service, svc_name, svc_url, service_push, request.db),
                     fallback=lambda: request.db.rollback(),
                     http_error=HTTPForbidden, msg_on_fail=s.Service_PATCH_ForbiddenResponseSchema.description,
                     content=err_svc_content)
    return ax.valid_http(http_success=HTTPOk, detail=s.Service_PATCH_OkResponseSchema.description,
                         content={"service": sf.format_service(service, show_private_url=True)})
Exemple #12
0
def delete_user_view(request):
    """
    Delete a user by name.
    """
    user = ar.get_user_matchdict_checked_or_logged(request)
    ax.evaluate_call(
        lambda: request.db.delete(user),
        fallback=lambda: request.db.rollback(),
        httpError=HTTPForbidden,
        msgOnFail=s.User_DELETE_ForbiddenResponseSchema.description)
    return ax.valid_http(httpSuccess=HTTPOk,
                         detail=s.User_DELETE_OkResponseSchema.description)
Exemple #13
0
 def test_evaluate_call_callable_incorrect_usage(self):
     """
     Verifies that incorrect usage of utility is raised accordingly.
     """
     utils.check_raises(
         lambda: ax.evaluate_call(int),
         HTTPInternalServerError,
         msg="invalid callable non-lambda 'call' should raise")
     utils.check_raises(
         lambda: ax.evaluate_call(lambda: int, fallback=int),  # noqa
         HTTPInternalServerError,
         msg="invalid callable non-lambda 'fallback' should raise")
Exemple #14
0
def assign_user_group(user, group, db_session):
    # type: (models.User, models.Group, Session) -> None
    """
    Creates a user-group relationship (user membership to a group).

    :returns: nothing - user-group is created.
    :raises HTTPError: corresponding error matching problem encountered.
    """
    ax.verify_param(user.id, param_compare=[usr.id for usr in group.users], not_in=True, with_param=False,
                    http_error=HTTPConflict, content={"user_name": user.user_name, "group_name": group.group_name},
                    msg_on_fail=s.UserGroups_POST_ConflictResponseSchema.description)
    ax.evaluate_call(lambda: db_session.add(models.UserGroup(group_id=group.id, user_id=user.id)),  # noqa
                     fallback=lambda: db_session.rollback(), http_error=HTTPForbidden,
                     msg_on_fail=s.UserGroups_POST_RelationshipForbiddenResponseSchema.description,
                     content={"user_name": user.user_name, "group_name": group.group_name})
Exemple #15
0
def resource_factory(**kwargs):
    resource_type = ax.evaluate_call(
        lambda: kwargs["resource_type"],
        http_error=HTTPInternalServerError,
        msg_on_fail="kwargs do not contain required 'resource_type'",
        content={"kwargs": repr(kwargs)})
    msg = "kwargs unpacking failed from specified 'resource_type' and 'RESOURCE_TYPE_DICT'"
    return ax.evaluate_call(
        lambda: RESOURCE_TYPE_DICT[resource_type](**kwargs),  # noqa
        http_error=HTTPInternalServerError,
        msg_on_fail=msg,
        content={
            "kwargs": repr(kwargs),
            "RESOURCE_TYPE_DICT": repr(RESOURCE_TYPE_DICT)
        })
Exemple #16
0
def get_user_service_permissions_view(request):
    """
    List all permissions a user has on a service.
    """
    user = ar.get_user_matchdict_checked_or_logged(request)
    service = ar.get_service_matchdict_checked(request)
    inherit_groups_perms = asbool(
        ar.get_query_param(request, ["inherit", "inherited"]))
    resolve_groups_perms = asbool(
        ar.get_query_param(request, ["resolve", "resolved"]))
    perm_type = PermissionType.INHERITED if inherit_groups_perms else PermissionType.DIRECT
    perms = ax.evaluate_call(
        lambda: uu.get_user_service_permissions(
            service=service,
            user=user,
            request=request,
            inherit_groups_permissions=inherit_groups_perms,
            resolve_groups_permissions=resolve_groups_perms),
        fallback=lambda: request.db.rollback(),
        http_error=HTTPNotFound,
        msg_on_fail=s.UserServicePermissions_GET_NotFoundResponseSchema.
        description,
        content={
            "service_name": str(service.resource_name),
            "user_name": str(user.user_name)
        })
    return ax.valid_http(
        http_success=HTTPOk,
        content=format_permissions(perms, perm_type),
        detail=s.UserServicePermissions_GET_OkResponseSchema.description)
Exemple #17
0
    def _add_service_magpie_and_phoenix(svc, svc_push, db):
        db.add(svc)
        if svc_push and svc.type in SERVICES_PHOENIX_ALLOWED:
            sync_services_phoenix(db.query(models.Service))

        # sometimes, resource ID is not updated, fetch the service to obtain it
        if not svc.resource_id:
            svc = ax.evaluate_call(
                lambda: models.Service.by_service_name(service_name,
                                                       db_session=db_session),
                fallback=lambda: db_session.rollback(),
                http_error=HTTPInternalServerError,
                msg_on_fail=s.Services_POST_InternalServerErrorResponseSchema.
                description,
                content={
                    "service_name": str(service_name),
                    "resource_id": svc.resource_id
                })
            ax.verify_param(
                svc.resource_id,
                not_none=True,
                param_compare=int,
                is_type=True,
                http_error=HTTPInternalServerError,
                msg_on_fail=s.Services_POST_InternalServerErrorResponseSchema.
                description,
                content={
                    "service_name": str(service_name),
                    "resource_id": svc.resource_id
                },
                param_name="service_name")
        return svc
Exemple #18
0
def get_service_type_resources_view(request):
    """
    List details of resource types supported under a specific service type.
    """
    def _get_resource_types_info(res_type_names):
        res_type_classes = [
            rtc for rtn, rtc in models.RESOURCE_TYPE_DICT.items()
            if rtn in res_type_names
        ]
        return [
            sf.format_service_resource_type(rtc,
                                            SERVICE_TYPE_DICT[service_type])
            for rtc in res_type_classes
        ]

    service_type = ar.get_value_matchdict_checked(request, "service_type")
    ax.verify_param(
        service_type,
        paramCompare=SERVICE_TYPE_DICT.keys(),
        isIn=True,
        httpError=HTTPNotFound,
        msgOnFail=s.ServiceTypeResources_GET_NotFoundResponseSchema.description
    )
    resource_types_names = ax.evaluate_call(
        lambda: SERVICE_TYPE_DICT[service_type].resource_type_names,
        httpError=HTTPForbidden,
        content={u"service_type": str(service_type)},
        msgOnFail=s.ServiceTypeResourceTypes_GET_ForbiddenResponseSchema.
        description)
    return ax.valid_http(
        httpSuccess=HTTPOk,
        detail=s.ServiceTypeResourceTypes_GET_OkResponseSchema.description,
        content={
            u"resource_types": _get_resource_types_info(resource_types_names)
        })
Exemple #19
0
def assign_user_group_view(request):
    """
    Assign a user to a group.
    """
    user = ar.get_user_matchdict_checked_or_logged(request)

    group_name = ar.get_value_multiformat_body_checked(request, "group_name")
    group = ax.evaluate_call(
        lambda: GroupService.by_group_name(group_name, db_session=request.db),
        fallback=lambda: request.db.rollback(),
        http_error=HTTPForbidden,
        msg_on_fail=s.UserGroups_POST_ForbiddenResponseSchema.description)
    ax.verify_param(
        group,
        not_none=True,
        http_error=HTTPNotFound,
        msg_on_fail=s.UserGroups_POST_GroupNotFoundResponseSchema.description)
    uu.assign_user_group(user, group, db_session=request.db)
    return ax.valid_http(
        http_success=HTTPCreated,
        detail=s.UserGroups_POST_CreatedResponseSchema.description,
        content={
            "user_name": user.user_name,
            "group_name": group.group_name
        })
Exemple #20
0
def sign_in(request):
    """
    Signs in a user session.
    """
    provider_name = ar.get_value_multiformat_body_checked(request, "provider_name", default=MAGPIE_DEFAULT_PROVIDER)
    provider_name = provider_name.lower()
    # magpie supports login from both username or corresponding email
    # therefore validate pattern combination manually after fetch otherwise email format fails patter match
    user_name = ar.get_value_multiformat_body_checked(request, "user_name", pattern=None)  # bad request if missing
    pattern = ax.EMAIL_REGEX if "@" in user_name else ax.PARAM_REGEX
    ax.verify_param(user_name, matches=True, param_compare=pattern, param_name="user_name",
                    http_error=HTTPUnprocessableEntity, msg_on_fail=s.UnprocessableEntityResponseSchema.description)
    verify_provider(provider_name)

    if provider_name in MAGPIE_INTERNAL_PROVIDERS.keys():
        # password can be None for external login, validate only here as needed
        password = ar.get_value_multiformat_body_checked(request, "password", pattern=None)
        # check manually to avoid inserting value in result body
        # obtain the raw path, without any '/magpie' prefix (if any), let 'application_url' handle it
        signin_internal_path = request.route_url("ziggurat.routes.sign_in", _app_url="")
        signin_internal_data = {"user_name": user_name, "password": password, "provider_name": provider_name}
        signin_sub_request = Request.blank(signin_internal_path, base_url=request.application_url,
                                           headers={"Accept": CONTENT_TYPE_JSON}, POST=signin_internal_data)
        signin_response = request.invoke_subrequest(signin_sub_request, use_tweens=True)
        if signin_response.status_code == HTTPOk.code:
            return convert_response(signin_response)
        login_failure(request, s.Signin_POST_UnauthorizedResponseSchema.description)

    elif provider_name in MAGPIE_EXTERNAL_PROVIDERS.keys():
        return ax.evaluate_call(lambda: process_sign_in_external(request, user_name, provider_name),
                                http_error=HTTPInternalServerError,
                                content={"user_name": user_name, "provider_name": provider_name},
                                msg_on_fail=s.Signin_POST_External_InternalServerErrorResponseSchema.description)
Exemple #21
0
def get_discoverable_group_by_name(group_name, db_session):
    # type: (Str, Session) -> models.Group
    """
    Obtains the requested discoverable group by name.

    .. note::
        For security reason, an existing group that is **NOT** discoverable will return NotFound instead of Forbidden.
        Otherwise we give an indication to a potentially non-admin user that *some group* of that name exists.

    :return: found group matched by name
    :raises HTTPNotFound: if the group cannot be found or if matched group name is not discoverable.
    """
    public_groups = get_discoverable_groups(db_session)
    found_group = ax.evaluate_call(
        lambda: [grp for grp in public_groups if grp.group_name == group_name],
        http_error=HTTPNotFound,
        msg_on_fail=s.RegisterGroup_NotFoundResponseSchema.description,
        content={"group_name": group_name})
    ax.verify_param(
        found_group,
        param_name="group_name",
        not_empty=True,
        http_error=HTTPNotFound,
        content_type=CONTENT_TYPE_JSON,
        msg_on_fail=s.RegisterGroup_NotFoundResponseSchema.description)
    return found_group[0]
Exemple #22
0
def get_permission_multiformat_body_checked(request, service_or_resource):
    # type: (Request, ServiceOrResourceType) -> PermissionSet
    """
    Retrieves the permission from the body and validates that it is allowed for the specified `service` or `resource`.

    Validation combines basic field checks followed by contextual values applicable for the `service` or `resource`.
    The permission can be provided either by literal string name (explicit or implicit format) or JSON object.

    .. seealso::
        - :func:`get_value_multiformat_body_checked`
    """
    # import here to avoid circular import error with undefined functions between (api_request, resource_utils)
    from magpie.api.management.resource.resource_utils import check_valid_service_or_resource_permission

    perm_key = "permission"
    permission = get_multiformat_body(request, perm_key)
    if not permission:
        perm_key = "permission_name"
        permission = get_multiformat_body(request, perm_key)
    if isinstance(permission, six.string_types):
        check_value(permission, perm_key)
    elif isinstance(permission, dict) and len(permission):
        for perm_sub_key, perm_sub_val in permission.items():
            if perm_sub_val is not None:
                check_value(perm_sub_val, "{}.{}".format(perm_key, perm_sub_key))
    else:
        ax.raise_http(http_error=HTTPBadRequest, content={perm_key: str(permission)},
                      detail=s.Permission_Check_BadRequestResponseSchema.description)
    perm = ax.evaluate_call(lambda: PermissionSet(permission),
                            http_error=HTTPUnprocessableEntity, content={perm_key: str(permission)},
                            msg_on_fail=s.UnprocessableEntityResponseSchema.description)
    check_valid_service_or_resource_permission(perm.name, service_or_resource, request.db)
    return perm
Exemple #23
0
def login_failure(request, reason=None):
    """
    Response from redirect upon login failure, either because of invalid or incorrect user credentials.

    .. seealso::
        - :func:`sign_in`
    """
    http_err = HTTPUnauthorized
    if reason is None:
        reason = s.Signin_POST_UnauthorizedResponseSchema.description
        try:
            user_name = ar.get_value_multiformat_body_checked(request, "user_name", default=None)
            ar.get_value_multiformat_body_checked(request, "password", default=None, pattern=None)
        except HTTPException:
            http_err = HTTPBadRequest
            reason = s.Signin_POST_BadRequestResponseSchema.description
        else:
            user_name_list = ax.evaluate_call(
                lambda: [user.user_name for user in UserService.all(models.User, db_session=request.db)],
                fallback=lambda: request.db.rollback(), http_error=HTTPForbidden,
                msg_on_fail=s.Signin_POST_ForbiddenResponseSchema.description)
            if user_name in user_name_list:
                http_err = HTTPInternalServerError
                reason = s.Signin_POST_Internal_InternalServerErrorResponseSchema.description
    content = ag.get_request_info(request, default_message=s.Signin_POST_UnauthorizedResponseSchema.description)
    content.setdefault("detail", str(reason))
    ax.raise_http(http_error=http_err, content=content, detail=s.Signin_POST_UnauthorizedResponseSchema.description)
Exemple #24
0
def sign_in(request):
    """
    Signs in a user session.
    """
    provider_name = get_value_multiformat_post_checked(request, "provider_name", default=MAGPIE_DEFAULT_PROVIDER)
    provider_name = provider_name.lower()
    user_name = get_value_multiformat_post_checked(request, "user_name")
    password = get_multiformat_post(request, "password")   # no check since password is None for external login
    verify_provider(provider_name)

    if provider_name in MAGPIE_INTERNAL_PROVIDERS.keys():
        # obtain the raw path, without any '/magpie' prefix (if any), let 'application_url' handle it
        signin_internal_path = request.route_url("ziggurat.routes.sign_in", _app_url="")
        signin_internal_data = {u"user_name": user_name, u"password": password, u"provider_name": provider_name}
        signin_sub_request = Request.blank(signin_internal_path, base_url=request.application_url,
                                           headers={"Accept": CONTENT_TYPE_JSON}, POST=signin_internal_data)
        signin_response = request.invoke_subrequest(signin_sub_request, use_tweens=True)
        if signin_response.status_code == HTTPOk.code:
            return convert_response(signin_response)
        login_failure(request, s.Signin_POST_UnauthorizedResponseSchema.description)

    elif provider_name in MAGPIE_EXTERNAL_PROVIDERS.keys():
        return ax.evaluate_call(lambda: process_sign_in_external(request, user_name, provider_name),
                                httpError=HTTPInternalServerError,
                                content={u"user_name": user_name, u"provider_name": provider_name},
                                msgOnFail=s.Signin_POST_External_InternalServerErrorResponseSchema.description)
Exemple #25
0
def format_resource(resource, permissions=None, basic_info=False):
    """
    Formats the ``resource`` information into JSON.
    """
    def fmt_res(res, perms, info):
        result = {
            u"resource_name": str(res.resource_name),
            u"resource_display_name": str(res.resource_display_name or res.resource_name),
            u"resource_type": str(res.resource_type),
            u"resource_id": res.resource_id
        }
        if not info:
            result.update({
                u"parent_id": res.parent_id,
                u"root_service_id": res.root_service_id,
                u"children": {},
                u"permission_names": list() if perms is None else format_permissions(perms)
            })
        return result

    return evaluate_call(
        lambda: fmt_res(resource, permissions, basic_info),
        httpError=HTTPInternalServerError,
        msgOnFail="Failed to format resource.",
        content={u"resource": repr(resource), u"permissions": repr(permissions), u"basic_info": str(basic_info)}
    )
Exemple #26
0
def get_user_service_permissions_view(request):
    """
    List all permissions a user has on a service.
    """
    user = ar.get_user_matchdict_checked_or_logged(request)
    service = ar.get_service_matchdict_checked(request)
    inherit_groups_perms = asbool(ar.get_query_param(request, "inherit"))
    perms = ax.evaluate_call(
        lambda: uu.get_user_service_permissions(service=service,
                                                user=user,
                                                request=request,
                                                inherit_groups_permissions=
                                                inherit_groups_perms),
        fallback=lambda: request.db.rollback(),
        httpError=HTTPNotFound,
        msgOnFail=s.UserServicePermissions_GET_NotFoundResponseSchema.
        description,
        content={
            u"service_name": str(service.resource_name),
            u"user_name": str(user.user_name)
        })
    return ax.valid_http(
        httpSuccess=HTTPOk,
        detail=s.UserServicePermissions_GET_OkResponseSchema.description,
        content={u"permission_names": sorted(p.value for p in perms)})
Exemple #27
0
def get_group_resource_permissions_response(group, resource, db_session):
    # type: (models.Group, models.Resource, Session) -> HTTPException
    """
    Get validated response with group resource permissions as content.

    :returns: valid HTTP response on successful operations.
    :raises HTTPException: error HTTP response of corresponding situation.
    """
    def get_grp_res_perms(grp, res, db):
        if res.owner_group_id == grp.id:
            # FIXME: no 'magpie.models.Resource.permissions' - ok for now because no owner handling...
            return models.RESOURCE_TYPE_DICT[res.type].permissions
        perms = db.query(models.GroupResourcePermission) \
                  .filter(models.GroupResourcePermission.resource_id == res.resource_id) \
                  .filter(models.GroupResourcePermission.group_id == grp.id)
        return [PermissionSet(p, typ=PermissionType.APPLIED) for p in perms]

    group_permissions = ax.evaluate_call(
        lambda: format_permissions(
            get_grp_res_perms(group, resource, db_session), PermissionType.
            APPLIED),
        http_error=HTTPInternalServerError,
        msg_on_fail=s.
        GroupResourcePermissions_InternalServerErrorResponseSchema.description,
        content={
            "group": repr(group),
            "resource": repr(resource)
        })
    return ax.valid_http(
        http_success=HTTPOk,
        detail=s.GroupResourcePermissions_GET_OkResponseSchema.description,
        content=group_permissions)
Exemple #28
0
def create_service_resource_view(request):
    """
    Register a new resource directly under a service or under one of its children resources.
    """
    service = ar.get_service_matchdict_checked(request)
    resource_name = ar.get_multiformat_body(request, "resource_name")
    resource_display_name = ar.get_multiformat_body(request, "resource_display_name", default=resource_name)
    resource_type = ar.get_multiformat_body(request, "resource_type")
    parent_id = ar.get_multiformat_body(request, "parent_id")  # no check because None/empty is allowed
    db_session = request.db
    if parent_id is None:
        parent_id = service.resource_id
    else:
        parent_id = ax.evaluate_call(lambda: int(parent_id),
                                     http_error=HTTPUnprocessableEntity,
                                     msg_on_fail=s.ServiceResources_POST_UnprocessableEntityResponseSchema.description)
        # validate target service is actually the root service of the provided parent resource ID
        root_service = ru.get_resource_root_service_by_id(parent_id, db_session=db_session)
        ax.verify_param(root_service, not_none=True, param_name="parent_id",
                        msg_on_fail=s.ServiceResources_POST_NotFoundResponseSchema.description,
                        http_error=HTTPNotFound)
        ax.verify_param(root_service.resource_id, is_equal=True,
                        param_compare=service.resource_id, param_name="parent_id",
                        msg_on_fail=s.ServiceResources_POST_ForbiddenResponseSchema.description,
                        http_error=HTTPForbidden)
    return ru.create_resource(resource_name, resource_display_name, resource_type,
                              parent_id=parent_id, db_session=db_session)
Exemple #29
0
def format_group(group, basic_info=False, public_info=False, db_session=None):
    # type: (Group, bool, bool, Optional[Session]) -> JSON
    """
    Obtains the JSON formatted group definition according to field selection flags.

    :param group: Group for which to provide details.
    :param basic_info:
        If ``True``, return only sufficient details to identify the group (useful for routes that refer to a group,
        but that are not requesting it specifically), or return full details (for routes that specifically request
        its information, e.g.: ``GET /groups/{grp}``).
    :param public_info:
        Indicate if the returned details are intended for public information (``True``) or admin-only (``False``).
        Only higher level users should be provided additional details to avoid leaking potentially sensitive parameters.
    :param db_session: Database connection to retrieve additional details (required when ``public_info=False``).
    """
    def fmt_grp(grp, is_basic, is_public):
        info = {"group_name": str(grp.group_name)}
        if not is_public:
            info["group_id"] = grp.id
        if is_basic:
            return info
        info["description"] = str(grp.description) if grp.description else None
        if is_public:
            return info
        info["discoverable"] = grp.discoverable
        info["priority"] = grp.priority
        info["member_count"] = grp.get_member_count(db_session)
        info["user_names"] = [usr.user_name for usr in grp.users]
        return info

    return evaluate_call(lambda: fmt_grp(group, basic_info, public_info),
                         http_error=HTTPInternalServerError,
                         msg_on_fail="Failed to format group.",
                         content={"group": repr(group)})
Exemple #30
0
def update_user_view(request):
    """
    Update user information by user name.
    """

    user_name = ar.get_value_matchdict_checked(request, key="user_name")
    ax.verify_param(
        user_name,
        paramCompare=get_constant("MAGPIE_LOGGED_USER"),
        notEqual=True,
        httpError=HTTPBadRequest,
        paramName="user_name",
        content={u"user_name": user_name},
        msgOnFail=s.Service_PUT_BadRequestResponseSchema_ReservedKeyword.
        description)

    user = ar.get_user_matchdict_checked(request, user_name_key="user_name")
    new_user_name = ar.get_multiformat_post(request,
                                            "user_name",
                                            default=user.user_name)
    new_email = ar.get_multiformat_post(request, "email", default=user.email)
    new_password = ar.get_multiformat_post(request,
                                           "password",
                                           default=user.user_password)
    uu.check_user_info(new_user_name,
                       new_email,
                       new_password,
                       group_name=new_user_name)

    update_username = user.user_name != new_user_name
    update_password = user.user_password != new_password
    update_email = user.email != new_email
    ax.verify_param(any([update_username, update_password, update_email]),
                    isTrue=True,
                    httpError=HTTPBadRequest,
                    content={u"user_name": user.user_name},
                    msgOnFail=s.User_PUT_BadRequestResponseSchema.description)

    if user.user_name != new_user_name:
        existing_user = ax.evaluate_call(
            lambda: UserService.by_user_name(new_user_name,
                                             db_session=request.db),
            fallback=lambda: request.db.rollback(),
            httpError=HTTPForbidden,
            msgOnFail=s.User_PUT_ForbiddenResponseSchema.description)
        ax.verify_param(
            existing_user,
            isNone=True,
            httpError=HTTPConflict,
            msgOnFail=s.User_PUT_ConflictResponseSchema.description)
        user.user_name = new_user_name
    if user.email != new_email:
        user.email = new_email
    if user.user_password != new_password and new_password is not None:
        UserService.set_password(user, new_password)
        UserService.regenerate_security_code(user)

    return ax.valid_http(httpSuccess=HTTPOk,
                         detail=s.Users_PUT_OkResponseSchema.description)