Example #1
0
def __extract_payload_from_request(trans, func, kwargs):
    content_type = trans.request.headers['content-type']
    if content_type.startswith('application/x-www-form-urlencoded') or content_type.startswith('multipart/form-data'):
        # If the content type is a standard type such as multipart/form-data, the wsgi framework parses the request body
        # and loads all field values into kwargs. However, kwargs also contains formal method parameters etc. which
        # are not a part of the request body. This is a problem because it's not possible to differentiate between values
        # which are a part of the request body, and therefore should be a part of the payload, and values which should not be
        # in the payload. Therefore, the decorated method's formal arguments are discovered through reflection and removed from
        # the payload dictionary. This helps to prevent duplicate argument conflicts in downstream methods.
        payload = kwargs.copy()
        named_args, _, _, _ = inspect.getargspec(func)
        for arg in named_args:
            payload.pop(arg, None)
        for k, v in payload.iteritems():
            if isinstance(v, (str, unicode)):
                try:
                    payload[k] = loads(v)
                except:
                    # may not actually be json, just continue
                    pass
        payload = util.recursively_stringify_dictionary_keys( payload )
    else:
        # Assume application/json content type and parse request body manually, since wsgi won't do it. However, the order of this check
        # should ideally be in reverse, with the if clause being a check for application/json and the else clause assuming a standard encoding
        # such as multipart/form-data. Leaving it as is for backward compatibility, just in case.
        payload = util.recursively_stringify_dictionary_keys( loads( trans.request.body ) )
    return payload
Example #2
0
def __extract_payload_from_request(trans, func, kwargs):
    content_type = trans.request.headers['content-type']
    if content_type.startswith(
            'application/x-www-form-urlencoded') or content_type.startswith(
                'multipart/form-data'):
        # If the content type is a standard type such as multipart/form-data, the wsgi framework parses the request body
        # and loads all field values into kwargs. However, kwargs also contains formal method parameters etc. which
        # are not a part of the request body. This is a problem because it's not possible to differentiate between values
        # which are a part of the request body, and therefore should be a part of the payload, and values which should not be
        # in the payload. Therefore, the decorated method's formal arguments are discovered through reflection and removed from
        # the payload dictionary. This helps to prevent duplicate argument conflicts in downstream methods.
        payload = kwargs.copy()
        named_args, _, _, _ = inspect.getargspec(func)
        for arg in named_args:
            payload.pop(arg, None)
        for k, v in payload.iteritems():
            if isinstance(v, (str, unicode)):
                try:
                    payload[k] = loads(v)
                except:
                    # may not actually be json, just continue
                    pass
        payload = util.recursively_stringify_dictionary_keys(payload)
    else:
        # Assume application/json content type and parse request body manually, since wsgi won't do it. However, the order of this check
        # should ideally be in reverse, with the if clause being a check for application/json and the else clause assuming a standard encoding
        # such as multipart/form-data. Leaving it as is for backward compatibility, just in case.
        payload = util.recursively_stringify_dictionary_keys(
            loads(trans.request.body))
    return payload
Example #3
0
 def decorator( self, trans, *args, **kwargs ):
     def error( environ, start_response ):
         start_response( error_status, [('Content-type', 'text/plain')] )
         return error_message
     error_status = '403 Forbidden'
     ## If there is a user, we've authenticated a session.
     if not trans.user and isinstance(trans.galaxy_session, Bunch):
         # If trans.user is already set, don't check for a key.
         # This happens when we're authenticating using session instead of an API key.
         # The Bunch clause is used to prevent the case where there's no user, but there is a real session.
         # DBTODO: This needs to be fixed when merging transaction types.
         if 'key' not in kwargs:
             error_message = 'No API key provided with request, please consult the API documentation.'
             return error
         try:
             provided_key = trans.sa_session.query( trans.app.model.APIKeys ).filter( trans.app.model.APIKeys.table.c.key == kwargs['key'] ).one()
         except NoResultFound:
             error_message = 'Provided API key is not valid.'
             return error
         if provided_key.user.deleted:
             error_message = 'User account is deactivated, please contact an administrator.'
             return error
         newest_key = provided_key.user.api_keys[0]
         if newest_key.key != provided_key.key:
             error_message = 'Provided API key has expired.'
             return error
         trans.set_user( provided_key.user )
     if trans.request.body:
         try:
             payload = util.recursively_stringify_dictionary_keys( simplejson.loads( trans.request.body ) )
             kwargs['payload'] = payload
         except ValueError:
             error_status = '400 Bad Request'
             error_message = 'Your request did not appear to be valid JSON, please consult the API documentation'
             return error
     trans.response.set_content_type( "application/json" )
     # Perform api_run_as processing, possibly changing identity
     if 'run_as' in kwargs:
         if not trans.user_can_do_run_as():
             error_message = 'User does not have permissions to run jobs as another user'
             return error
         try:
             decoded_user_id = trans.security.decode_id( kwargs['run_as'] )
         except TypeError:
             trans.response.status = 400
             return "Malformed user id ( %s ) specified, unable to decode." % str( kwargs['run_as'] )
         try:
             user = trans.sa_session.query( trans.app.model.User ).get( decoded_user_id )
             trans.api_inherit_admin = trans.user_is_admin()
             trans.set_user(user)
         except:
             trans.response.status = 400
             return "That user does not exist."
     try:
         if trans.debug:
             return simplejson.dumps( func( self, trans, *args, **kwargs ), indent=4, sort_keys=True )
         else:
             return simplejson.dumps( func( self, trans, *args, **kwargs ) )
     except paste.httpexceptions.HTTPException:
         raise # handled
     except:
         log.exception( 'Uncaught exception in exposed API method:' )
         raise paste.httpexceptions.HTTPServerError()