Ejemplo n.º 1
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)})
Ejemplo n.º 2
0
def get_services_runner(request):
    """
    Generates services response format from request conditions.

    Obtains the full or filtered list of services categorized by type, or listed as flat list according to request path
    and query parameters.
    """
    service_type_filter = request.matchdict.get("service_type")  # no check because None/empty is for 'all services'
    services_as_list = asbool(ar.get_query_param(request, "flatten", False))

    if not service_type_filter:
        service_types = SERVICE_TYPE_DICT.keys()
    else:
        ax.verify_param(service_type_filter, param_compare=SERVICE_TYPE_DICT.keys(), is_in=True,
                        http_error=HTTPBadRequest, msg_on_fail=s.Services_GET_BadRequestResponseSchema.description,
                        content={"service_type": str(service_type_filter)}, content_type=CONTENT_TYPE_JSON)
        service_types = [service_type_filter]

    svc_content = [] if services_as_list else {}  # type: Union[List[JSON], JSON]
    for service_type in service_types:
        services = su.get_services_by_type(service_type, db_session=request.db)
        if not services_as_list:
            svc_content[service_type] = {}
        for service in services:
            svc_fmt = sf.format_service(service, show_private_url=True)
            if services_as_list:
                svc_content.append(svc_fmt)  # pylint: disable=E1101
            else:
                svc_content[service_type][service.resource_name] = svc_fmt

    return ax.valid_http(http_success=HTTPOk, content={"services": svc_content},
                         detail=s.Services_GET_OkResponseSchema.description)
Ejemplo n.º 3
0
def get_services_runner(request):
    service_type_filter = request.matchdict.get(
        "service_type")  # no check because None/empty is for 'all services'
    json_response = {}
    if not service_type_filter:
        service_types = SERVICE_TYPE_DICT.keys()
    else:
        ax.verify_param(
            service_type_filter,
            paramCompare=SERVICE_TYPE_DICT.keys(),
            isIn=True,
            httpError=HTTPBadRequest,
            msgOnFail=s.Services_GET_BadRequestResponseSchema.description,
            content={u"service_type": str(service_type_filter)},
            contentType=CONTENT_TYPE_JSON)
        service_types = [service_type_filter]

    for service_type in service_types:
        services = su.get_services_by_type(service_type, db_session=request.db)
        json_response[service_type] = {}
        for service in services:
            json_response[service_type][
                service.resource_name] = sf.format_service(
                    service, show_private_url=True)

    return ax.valid_http(httpSuccess=HTTPOk,
                         content={u"services": json_response},
                         detail=s.Services_GET_OkResponseSchema.description)
Ejemplo n.º 4
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)
Ejemplo n.º 5
0
def get_service_view(request):
    """
    Get a service information.
    """
    service = ar.get_service_matchdict_checked(request)
    service_info = sf.format_service(service, show_private_url=True,
                                     show_resources_allowed=True, show_configuration=True)
    return ax.valid_http(http_success=HTTPOk, detail=s.Service_GET_OkResponseSchema.description,
                         content={"service": service_info})
Ejemplo n.º 6
0
def get_user_services(user,
                      request,
                      cascade_resources=False,
                      inherit_groups_permissions=False,
                      format_as_list=False):
    # type: (models.User, Request, bool, bool, bool) -> UserServicesType
    """
    Returns services by type with corresponding services by name containing sub-dict information.

    :param user: user for which to find services
    :param request: request with database session connection
    :param cascade_resources:
        If `False`, return only services with *Direct* user permissions on their corresponding service-resource.
        Otherwise, return every service that has at least one sub-resource with user permissions.
    :param inherit_groups_permissions:
        If `False`, return only user-specific service/sub-resources permissions.
        Otherwise, resolve inherited permissions using all groups the user is member of.
    :param format_as_list:
        returns as list of service dict information (not grouped by type and by name)
    :return: only services which the user as *Direct* or *Inherited* permissions, according to `inherit_from_resources`
    :rtype:
        dict of services by type with corresponding services by name containing sub-dict information,
        unless `format_as_dict` is `True`
    """
    db_session = request.db
    resource_type = None if cascade_resources else [
        models.Service.resource_type
    ]
    res_perm_dict = get_user_resources_permissions_dict(
        user,
        resource_types=resource_type,
        request=request,
        inherit_groups_permissions=inherit_groups_permissions)

    services = {}
    for resource_id, perms in res_perm_dict.items():
        svc = ResourceService.by_resource_id(resource_id=resource_id,
                                             db_session=db_session)
        if svc.resource_type != models.Service.resource_type and cascade_resources:
            svc = get_resource_root_service(svc, request)
            perms = svc.permissions
        if svc.type not in services:
            services[svc.type] = {}
        if svc.resource_name not in services[svc.type]:
            services[svc.type][svc.resource_name] = format_service(
                svc, perms, show_private_url=False)

    if not format_as_list:
        return services

    services_list = list()
    for svc_type in services:
        for svc_name in services[svc_type]:
            services_list.append(services[svc_type][svc_name])
    return services_list
Ejemplo n.º 7
0
def get_service_permissions_view(request):
    """
    List all applicable permissions for a service.
    """
    service = ar.get_service_matchdict_checked(request)
    svc_content = sf.format_service(service, show_private_url=True)
    svc_perms = ax.evaluate_call(lambda: [p.value for p in SERVICE_TYPE_DICT[service.type].permissions],
                                 fallback=request.db.rollback(), http_error=HTTPBadRequest, content=svc_content,
                                 msg_on_fail=s.ServicePermissions_GET_BadRequestResponseSchema.description)
    return ax.valid_http(http_success=HTTPOk, detail=s.ServicePermissions_GET_OkResponseSchema.description,
                         content=format_permissions(svc_perms, PermissionType.ALLOWED))
Ejemplo n.º 8
0
def get_group_services(resources_permissions_dict, db_session):
    # type: (JSON, Session) -> JSON
    """
    Nest and regroup the resource permissions under corresponding root service types.
    """
    grp_svc_dict = {}
    for res_id, perms in resources_permissions_dict.items():
        svc = ResourceService.by_resource_id(resource_id=res_id, db_session=db_session)
        svc_type = str(svc.type)
        svc_name = str(svc.resource_name)
        if svc_type not in grp_svc_dict:
            grp_svc_dict[svc_type] = {}
        grp_svc_dict[svc_type][svc_name] = format_service(svc, perms, show_private_url=False)
    return grp_svc_dict
Ejemplo n.º 9
0
def get_group_service_permissions_response(group, service, db_session):
    # type: (models.Group, models.Service, Session) -> HTTPException
    """
    Get validated response of found group service permissions.

    :returns: valid HTTP response on successful operations.
    :raises HTTPException: error HTTP response of corresponding situation.
    """
    svc_perms_found = ax.evaluate_call(
        lambda: format_permissions(get_group_service_permissions(group, service, db_session)),
        httpError=HTTPInternalServerError,
        msgOnFail=s.GroupServicePermissions_GET_InternalServerErrorResponseSchema.description,
        content={u"group": format_group(group, basic_info=True), u"service": format_service(service)})
    return ax.valid_http(httpSuccess=HTTPOk, detail=s.GroupServicePermissions_GET_OkResponseSchema.description,
                         content={u"permission_names": svc_perms_found})
Ejemplo n.º 10
0
def create_service(service_name, service_type, service_url, service_push,
                   service_config, db_session):
    # type: (Str, Str, Str, bool, Optional[JSON], Session) -> HTTPException
    """
    Generates an instance to register a new service.
    """
    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

    ax.verify_param(
        service_type,
        not_none=True,
        not_empty=True,
        is_type=True,
        param_name="service_type",
        param_compare=six.string_types,
        http_error=HTTPBadRequest,
        msg_on_fail=s.Services_POST_BadRequestResponseSchema.description)
    ax.verify_param(
        service_type,
        is_in=True,
        param_compare=SERVICE_TYPE_DICT.keys(),
        param_name="service_type",
        http_error=HTTPBadRequest,
        msg_on_fail=s.Services_POST_BadRequestResponseSchema.description)
    ax.verify_param(service_url,
                    matches=True,
                    param_compare=ax.URL_REGEX,
                    param_name="service_url",
                    http_error=HTTPBadRequest,
                    msg_on_fail=s.
                    Services_POST_Params_BadRequestResponseSchema.description)
    ax.verify_param(service_name,
                    not_empty=True,
                    not_none=True,
                    matches=True,
                    param_name="service_name",
                    param_compare=ax.PARAM_REGEX,
                    http_error=HTTPBadRequest,
                    msg_on_fail=s.
                    Services_POST_Params_BadRequestResponseSchema.description)
    ax.verify_param(
        models.Service.by_service_name(service_name, db_session=db_session),
        is_none=True,
        param_name="service_name",
        with_param=False,
        content={"service_name": str(service_name)},
        http_error=HTTPConflict,
        msg_on_fail=s.Services_POST_ConflictResponseSchema.description)
    if service_config is not None:
        ax.verify_param(
            service_config,
            param_name="configuration",
            param_compare=dict,
            is_type=True,
            http_error=HTTPUnprocessableEntity,
            msg_on_fail=s.
            Service_CheckConfig_UnprocessableEntityResponseSchema.description)
    service = ax.evaluate_call(
        lambda: models.Service(resource_name=str(service_name),
                               resource_type=models.Service.resource_type_name,
                               configuration=service_config,
                               url=str(service_url),
                               type=str(service_type)),  # noqa
        fallback=lambda: db_session.rollback(),
        http_error=HTTPForbidden,
        msg_on_fail=s.Services_POST_UnprocessableEntityResponseSchema.
        description,
        content={
            "service_name": str(service_name),
            "resource_type": models.Service.resource_type_name,
            "service_url": str(service_url),
            "service_type": str(service_type)
        })

    service = ax.evaluate_call(
        lambda: _add_service_magpie_and_phoenix(service, service_push,
                                                db_session),
        fallback=lambda: db_session.rollback(),
        http_error=HTTPForbidden,
        msg_on_fail=s.Services_POST_ForbiddenResponseSchema.description,
        content=format_service(service, show_private_url=True))
    return ax.valid_http(
        http_success=HTTPCreated,
        detail=s.Services_POST_CreatedResponseSchema.description,
        content={"service": format_service(service, show_private_url=True)})
Ejemplo n.º 11
0
def create_service(service_name, service_type, service_url, service_push,
                   db_session):
    # type: (Str, Str, Str, bool, Session) -> HTTPException
    """
    Generates an instance to register a new service.
    """
    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(),
                httpError=HTTPInternalServerError,
                msgOnFail=s.Services_POST_InternalServerErrorResponseSchema.
                description,
                content={
                    u'service_name': str(service_name),
                    u'resource_id': svc.resource_id
                })
            ax.verify_param(
                svc.resource_id,
                notNone=True,
                paramCompare=int,
                ofType=True,
                httpError=HTTPInternalServerError,
                msgOnFail=s.Services_POST_InternalServerErrorResponseSchema.
                description,
                content={
                    u'service_name': str(service_name),
                    u'resource_id': svc.resource_id
                },
                paramName=u'service_name')
        return svc

    # noinspection PyArgumentList
    service = ax.evaluate_call(
        lambda: models.Service(resource_name=str(service_name),
                               resource_type=models.Service.resource_type_name,
                               url=str(service_url),
                               type=str(service_type)),
        fallback=lambda: db_session.rollback(),
        httpError=HTTPForbidden,
        msgOnFail=s.Services_POST_UnprocessableEntityResponseSchema.
        description,
        content={
            u'service_name': str(service_name),
            u'resource_type': models.Service.resource_type_name,
            u'service_url': str(service_url),
            u'service_type': str(service_type)
        })

    service = ax.evaluate_call(
        lambda: _add_service_magpie_and_phoenix(service, service_push,
                                                db_session),
        fallback=lambda: db_session.rollback(),
        httpError=HTTPForbidden,
        msgOnFail=s.Services_POST_ForbiddenResponseSchema.description,
        content=format_service(service, show_private_url=True))
    return ax.valid_http(
        httpSuccess=HTTPCreated,
        detail=s.Services_POST_CreatedResponseSchema.description,
        content={u'service': format_service(service, show_private_url=True)})
Ejemplo n.º 12
0
def get_user_services(user, request, cascade_resources=False, format_as_list=False,
                      inherit_groups_permissions=False, resolve_groups_permissions=False):
    # type: (models.User, Request, bool, bool, bool, bool) -> UserServicesType
    """
    Returns services by type with corresponding services by name containing sub-dict information.

    .. seealso::
        :func:`regroup_permissions_by_resource`

    :param user: user for which to find services
    :param request: request with database session connection
    :param cascade_resources:
        If ``False``, return only services which the :term:`User` has :term:`Immediate Permissions` on specialized
        top-level resources corresponding to a :term:`Service`.
        Otherwise, return every service that has at least one sub-resource with permissions (children at any-level).
        In both cases, the *permissions* looked for consider either only :term:`Direct Permissions` or any
        :term:`Inherited Permissions` according to the value of :paramref:`inherit_groups_permissions`.
    :param inherit_groups_permissions:
        If ``False``, return only user-specific service/sub-resources :term:`Direct Permissions`.
        Otherwise, resolve :term:`Inherited Permissions` using all groups the user is member of.
    :param resolve_groups_permissions:
        Whether to combine :term:`Direct Permissions` and :term:`Inherited Permissions` for respective resources or not.
    :param format_as_list:
        returns as list of service dict information (not grouped by type and by name)
    :return:
        Only services which the user as :term:`Direct Permissions` or considering all tree hierarchy,
        and for each case, either considering only user permissions or every :term:`Inherited Permissions`,
        according to provided options.
    :rtype:
        Mapping of services by type to corresponding services by name containing each sub-mapping of their information,
        unless :paramref:`format_as_list` is ``True``, in which case a flat list of service information is returned.
    """
    db_session = request.db
    resource_type = None if cascade_resources else [models.Service.resource_type]
    res_perm_dict = get_user_resources_permissions_dict(user, resource_types=resource_type, request=request,
                                                        inherit_groups_permissions=inherit_groups_permissions,
                                                        resolve_groups_permissions=resolve_groups_permissions)
    perm_type = PermissionType.INHERITED if inherit_groups_permissions else PermissionType.DIRECT
    services = {}
    for resource_id, perms in res_perm_dict.items():
        resource = ResourceService.by_resource_id(resource_id=resource_id, db_session=db_session)
        is_service = resource.resource_type == models.Service.resource_type_name

        if not is_service:
            # if any children resource had user/group permissions, minimally return its root service without
            # any immediate permission, otherwise (cascade off) it is skipped and not returned at all in response
            if not cascade_resources:
                continue
            perms = []

        svc = ru.get_resource_root_service_impl(resource, request)
        if svc.service_type not in services:
            services[svc.service_type] = {}
        svc_name = svc.service.resource_name
        svc_type = svc.service_type

        # if service was not already added, add it (could be directly its permissions, or empty via children resource)
        # otherwise, set explicit immediate permissions on service instead of empty children resource permissions
        if svc_name not in services[svc_type] or is_service:
            svc_json = format_service(svc.service, perms, perm_type, show_private_url=False)
            services[svc_type][svc_name] = svc_json

    if not format_as_list:
        return services

    services_list = list()
    for svc_type in services:
        for svc_name in services[svc_type]:
            services_list.append(services[svc_type][svc_name])
    return services_list
Ejemplo n.º 13
0
def magpie_register_permissions_from_config(permissions_config,
                                            magpie_url=None,
                                            db_session=None):
    # type: (Union[Str, ConfigDict], Optional[Str], Optional[Session]) -> None
    """
    Applies permissions specified in configuration.

    :param permissions_config: file path to 'permissions' config or JSON/YAML equivalent pre-loaded.
    :param magpie_url: URL to magpie instance (when using requests; default: `magpie.url` from this app's config).
    :param db_session: db session to use instead of requests to directly create/remove permissions with config.

    .. seealso::
        `magpie/permissions.cfg` for specific parameters and operational details.
    """
    permissions = _load_config(permissions_config, "permissions")
    if not permissions:
        LOGGER.warning("Permissions configuration are empty.")
        return

    if use_request(db_session):
        magpie_url = magpie_url or get_magpie_url()
        settings = {'magpie.url': magpie_url}
        logging.debug(
            "Editing permissions using requests to [{}]...".format(magpie_url))
        err_msg = "Invalid credentials to register Magpie permissions."
        cookies_or_session = get_admin_cookies(settings, raise_message=err_msg)
    else:
        logging.debug("Editing permissions using db session...")
        cookies_or_session = db_session

    logging.info("Found {} permissions to update.".format(len(permissions)))
    for i, perm_cfg in enumerate(permissions):
        # parameter validation
        if not isinstance(perm_cfg, dict) or not all(
                f in perm_cfg for f in ["permission", "service"]):
            warn_permission(
                "Invalid permission format for [{!s}]".format(perm_cfg), i)
            continue
        if perm_cfg["permission"] not in Permission.values():
            warn_permission(
                "Unknown permission [{!s}]".format(perm_cfg['permission']), i)
            continue
        usr_name = perm_cfg.get("user")
        grp_name = perm_cfg.get("group")
        if not any([usr_name, grp_name]):
            warn_permission("Missing required user and/or group field.", i)
            continue
        if "action" not in perm_cfg:
            warn_permission("Unspecified action",
                            i,
                            trail="using default (create)...")
            perm_cfg["action"] = "create"
        if perm_cfg["action"] not in ["create", "remove"]:
            warn_permission("Unknown action [{!s}]".format(perm_cfg["action"]),
                            i)
            continue

        # retrieve service for permissions validation
        svc_name = perm_cfg["service"]
        if use_request(cookies_or_session):
            svc_path = magpie_url + ServiceAPI.path.format(
                service_name=svc_name)
            svc_resp = requests.get(svc_path, cookies=cookies_or_session)
            if svc_resp.status_code != 200:
                warn_permission("Unknown service [{!s}]".format(svc_name), i)
                continue
            service_info = get_json(svc_resp)[svc_name]
        else:
            transaction.commit(
            )  # force any pending transaction to be applied to find possible dependencies
            svc = models.Service.by_service_name(svc_name,
                                                 db_session=cookies_or_session)
            if not svc:
                warn_permission(
                    "Unknown service [{!s}]. Can't edit permissions without service."
                    .format(svc_name), i)
                continue
            from magpie.api.management.service.service_formats import format_service
            service_info = format_service(svc)

        # apply permission config
        resource_id, found = parse_resource_path(perm_cfg, i, service_info,
                                                 cookies_or_session,
                                                 magpie_url)
        if found:
            if not resource_id:
                resource_id = service_info["resource_id"]
            apply_permission_entry(perm_cfg, i, resource_id,
                                   cookies_or_session, magpie_url)

    if not use_request(cookies_or_session):
        transaction.commit()
    logging.info("Done processing permissions.")
Ejemplo n.º 14
0
def update_service_view(request):
    """
    Update a service information.
    """
    service = ar.get_service_matchdict_checked(request)
    service_push = asbool(
        ar.get_multiformat_post(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_post(request, "service_name"),
                             service.resource_name)
    svc_url = select_update(ar.get_multiformat_post(request, "service_url"),
                            service.url)
    ax.verify_param(
        svc_name,
        paramCompare="types",
        notEqual=True,
        paramName="service_name",
        httpError=HTTPBadRequest,
        msgOnFail=s.Service_PUT_BadRequestResponseSchema_ReservedKeyword.
        description)
    ax.verify_param(
        svc_name == service.resource_name and svc_url == service.url,
        notEqual=True,
        paramCompare=True,
        paramName="service_name/service_url",
        httpError=HTTPBadRequest,
        msgOnFail=s.Service_PUT_BadRequestResponseSchema.description)

    if svc_name != service.resource_name:
        all_svc_names = list()
        for svc_type in SERVICE_TYPE_DICT:
            for svc in su.get_services_by_type(svc_type,
                                               db_session=request.db):
                all_svc_names.append(svc.resource_name)
        ax.verify_param(
            svc_name,
            notIn=True,
            paramCompare=all_svc_names,
            httpError=HTTPConflict,
            msgOnFail=s.Service_PUT_ConflictResponseSchema.description,
            content={u"service_name": str(svc_name)})

    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 = {
        u"service": old_svc_content,
        u"new_service_name": svc_name,
        u"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(),
        httpError=HTTPForbidden,
        msgOnFail=s.Service_PUT_ForbiddenResponseSchema.description,
        content=err_svc_content)
    return ax.valid_http(httpSuccess=HTTPOk,
                         detail=s.Service_PUT_OkResponseSchema.description,
                         content={
                             u"service":
                             sf.format_service(service, show_private_url=True)
                         })