Beispiel #1
0
def _assert_if_match(request: web.Request, etag: T.Union[None, bool, str],
                     require: bool):
    # The If-Match: header is commonly used in non-safe HTTP requests to prevent
    # lost update problems.
    etags = _parse_if_header(request, 'If-Match')

    if etags is None:
        if require:
            raise web.HTTPPreconditionRequired(text='If-Match')
        return
    if etags is _STAR:
        if etag is None or etag is False:
            raise web.HTTPPreconditionFailed()
        if etag is True or require is False:
            return
        raise web.HTTPPreconditionRequired(
            text='If-Match: * is too generic for this resource.')
    # From here on, `etags` can only be a set().
    if etag is True or etag is False:
        raise web.HTTPPreconditionFailed(
            text="Resource doesn't support If-Match header.")
    # From here on, `etag` can only be `None` or a valid ETag string:
    if etag is None:
        raise web.HTTPNotFound()
    if etag not in etags:
        raise web.HTTPPreconditionFailed()
Beispiel #2
0
def abort(code):
    if code == 400: return web.HTTPBadRequest()
    elif code == 401: return web.HTTPUnauthorized()
    elif code == 402: return web.HTTPPaymentRequired()
    elif code == 403: return web.HTTPForbidden()
    elif code == 404: return web.HTTPNotFound()
    elif code == 405: return web.HTTPMethodNotAllowed()
    elif code == 406: return web.HTTPNotAcceptable()
    elif code == 407: return web.HTTPProxyAuthenticationRequired()
    elif code == 408: return web.HTTPRequestTimeout()
    elif code == 409: return web.HTTPConflict()
    elif code == 410: return web.HTTPGone()
    elif code == 411: return web.HTTPLengthRequired()
    elif code == 412: return web.HTTPPreconditionFailed()
    elif code == 413: return web.HTTPRequestEntityTooLarge()
    elif code == 414: return web.HTTPRequestURITooLong()
    elif code == 415: return web.HTTPUnsupportedMediaType()
    elif code == 416: return web.HTTPRequestRangeNotSatisfiable()
    elif code == 417: return web.HTTPExpectationFailed()
    elif code == 421: return web.HTTPMisdirectedRequest()
    elif code == 422: return web.HTTPUnprocessableEntity()
    elif code == 424: return web.HTTPFailedDependency()
    elif code == 426: return web.HTTPUpgradeRequired()
    elif code == 428: return web.HTTPPreconditionRequired()
    elif code == 429: return web.HTTPTooManyRequests()
    elif code == 431: return web.HTTPRequestHeaderFieldsTooLarge()
    elif code == 451: return web.HTTPUnavailableForLegalReasons()
    else: return web.HTTPBadRequest()
Beispiel #3
0
def _assert_if_none_match(request: web.Request, etag: T.Union[None, bool, str],
                          require: bool):
    # The If-None-Match: header is used in two scenarios:
    # 1. GET requests by a caching client. In this case, the client will
    #    normally provide a list of (cached) ETags.
    # 2. PUT requests, where the client intends to create a new resource and
    #    wants to avoid overwriting an existing resource. In this case, the
    #    client will normally provide only the asterisk "*" character.
    etags = _parse_if_header(request, 'If-None-Match')
    if require and etags is None:
        raise web.HTTPPreconditionRequired(text='If-None-Match')
    if etags is None or etag is False or etag is None:
        return
    if etags is _STAR:
        raise web.HTTPPreconditionFailed()
    # From here on, we know that etags is a set of strings.
    if etag is True:
        raise web.HTTPPreconditionFailed(
            text="Resource doesn't support ETags.")
    # From here on, we know that etag is a string:
    if etag in etags:
        if request.method in {'GET', 'HEAD'}:
            raise web.HTTPNotModified()
        else:
            raise web.HTTPPreconditionFailed()
Beispiel #4
0
    async def put(self):
        if_match = self.request.headers.get('if-match', '')
        if_none_match = self.request.headers.get('if-none-match', '')
        if if_match == '' and if_none_match == '':
            raise web.HTTPPreconditionRequired()
        assert_preconditions(self.request, await self.etag())
        if not re.match(r'application/(?:hal\+)?json(?:$|;)',
                        self.request.content_type):
            raise web.HTTPUnsupportedMediaType()
        try:
            request_body_json = json_loads(await self.request.text())
        except:
            raise web.HTTPBadRequest()
        # self.request.app['swagger'].validate_definition('Account', request_body_json)
        existing_roles = set(
            self.request.app['config']['authz_admin']['roles'].keys())
        try:
            roles = request_body_json['_links']['role']
            assert isinstance(roles, list)
        except:
            raise web.HTTPBadRequest(
                text="No '#/_links/role' array in request.") from None
        new_roles = set()
        try:
            for link_object in roles:
                role = web.URL(link_object['href']).name
                assert role in existing_roles
                new_roles.add(role)
        except:
            raise web.HTTPBadRequest(
                text=
                "Not all roles are valid HALJSON link objects to an existing role."
            ) from None

        if await self.data() is None:
            try:
                log_id = await database.create_account(self.request,
                                                       self['account'],
                                                       new_roles)
            except database.PreconditionFailed:
                raise web.HTTPPreconditionFailed() from None
            status = 201
            headers = {
                'Location': self.rel_url.raw_path,
                'ETag': etag_from_int(log_id)
            }
        else:
            try:
                log_id = await database.update_account(self.request, self,
                                                       new_roles)
            except database.PreconditionFailed:
                raise web.HTTPPreconditionFailed() from None
            status = 204
            headers = {'ETag': etag_from_int(log_id)}
        return web.Response(status=status, headers=headers)
Beispiel #5
0
 async def wrapper(self, *args, **kwargs):
     etag = await self.etag()
     request = self.request
     if_match = _assert_if_match(request=request,
                                 etag=etag,
                                 deny_asterisk=required,
                                 allow_weak=allow_weak)
     if_none_match = _assert_if_none_match(request=request,
                                           etag=etag,
                                           allow_weak=allow_weak)
     safe_methods = (_HTTP_SAFE_METHODS_INCL_POST
                     if post_is_safe else _HTTP_SAFE_METHODS_EXCL_POST)
     if request.method not in safe_methods and required and \
        not if_match and not if_none_match:
         raise web.HTTPPreconditionRequired()
     return await f(self, *args, **kwargs)
Beispiel #6
0
 def error(self,
           request: web.Request = None,
           response: dict = {},
           exception: Exception = None,
           state: int = 400,
           headers: dict = {},
           **kwargs) -> web.Response:
     # TODO: process the exception object
     response_obj = {"status": "Failed"}
     if not request:
         request = self.request
     if exception:
         response_obj["reason"] = str(exception)
     args = {**kwargs}
     if isinstance(response, dict):
         response_obj = {**response_obj, **response}
         args["content_type"] = "application/json"
         args["text"] = json.dumps(response_obj)
     else:
         args["body"] = response
     # defining the error
     if state == 400:  # bad request
         obj = web.HTTPBadRequest(**args)
     elif state == 401:  # unauthorized
         obj = web.HTTPUnauthorized(**args)
     elif state == 403:  # forbidden
         obj = web.HTTPForbidden(**args)
     elif state == 404:  # not found
         obj = web.HTTPNotFound(**args)
     elif state == 406:
         obj = web.HTTPNotAcceptable(**args)
     elif state == 412:
         obj = web.HTTPPreconditionFailed(**args)
     elif state == 428:
         obj = web.HTTPPreconditionRequired(**args)
     else:
         obj = web.HTTPBadRequest(**args)
     for header, value in headers.items():
         obj.headers[header] = value
     return obj