Ejemplo n.º 1
0
def normalizeQuery(path, query, remove=('signature',), separate=False):
    """Normalize request path and query so it can be used for caching and signing

    Returns a string consisting of path and sorted query string.
    Dynamic arguments like signature and timestamp are removed from the query string.
    """
    queryParams = remove_lists(parse_qs(query))
    if remove:
        for key in remove:
            queryParams.pop(key, None)
    sortedQuery = sorted(queryParams.items(), key=lambda x: x[0].lower())
    if separate:
        return path, sortedQuery and urllib.urlencode(sortedQuery)
    elif sortedQuery:
        return '%s?%s' % (path, urllib.urlencode(sortedQuery))
    else:
        return path
Ejemplo n.º 2
0
def handler(req, **params):
    ContextManager.destroy()
    logger = Logger.get('httpapi')
    path, query = req.URLFields['PATH_INFO'], req.URLFields['QUERY_STRING']
    if req.method == 'POST':
        # Convert POST data to a query string
        queryParams = dict(req.form)
        for key, value in queryParams.iteritems():
            queryParams[key] = [str(value)]
        query = urllib.urlencode(remove_lists(queryParams))
    else:
        # Parse the actual query string
        queryParams = parse_qs(query)

    dbi = DBMgr.getInstance()
    dbi.startRequest()
    minfo = HelperMaKaCInfo.getMaKaCInfoInstance()
    if minfo.getRoomBookingModuleActive():
        Factory.getDALManager().connect()

    apiKey = get_query_parameter(queryParams, ['ak', 'apikey'], None)
    cookieAuth = get_query_parameter(queryParams, ['ca', 'cookieauth'], 'no') == 'yes'
    signature = get_query_parameter(queryParams, ['signature'])
    timestamp = get_query_parameter(queryParams, ['timestamp'], 0, integer=True)
    noCache = get_query_parameter(queryParams, ['nc', 'nocache'], 'no') == 'yes'
    pretty = get_query_parameter(queryParams, ['p', 'pretty'], 'no') == 'yes'
    onlyPublic = get_query_parameter(queryParams, ['op', 'onlypublic'], 'no') == 'yes'
    onlyAuthed = get_query_parameter(queryParams, ['oa', 'onlyauthed'], 'no') == 'yes'

    # Get our handler function and its argument and response type
    hook, dformat = HTTPAPIHook.parseRequest(path, queryParams)
    if hook is None or dformat is None:
        raise apache.SERVER_RETURN, apache.HTTP_NOT_FOUND

    # Disable caching if we are not just retrieving data (or the hook requires it)
    if req.method == 'POST' or hook.NO_CACHE:
        noCache = True

    ak = error = result = None
    ts = int(time.time())
    typeMap = {}
    try:
        session = None
        if cookieAuth:
            session = getSessionForReq(req)
            if not session.getUser():  # ignore guest sessions
                session = None

        if apiKey or not session:
            # Validate the API key (and its signature)
            ak, enforceOnlyPublic = checkAK(apiKey, signature, timestamp, path, query)
            if enforceOnlyPublic:
                onlyPublic = True
            # Create an access wrapper for the API key's user
            aw = buildAW(ak, req, onlyPublic)
            # Get rid of API key in cache key if we did not impersonate a user
            if ak and aw.getUser() is None:
                cacheKey = normalizeQuery(path, query,
                                          remove=('ak', 'apiKey', 'signature', 'timestamp', 'nc', 'nocache',
                                                  'oa', 'onlyauthed'))
            else:
                cacheKey = normalizeQuery(path, query,
                                          remove=('signature', 'timestamp', 'nc', 'nocache', 'oa', 'onlyauthed'))
                if signature:
                    # in case the request was signed, store the result under a different key
                    cacheKey = 'signed_' + cacheKey
        else:
            # We authenticated using a session cookie.
            if Config.getInstance().getCSRFLevel() >= 2:
                token = req.headers_in.get('X-CSRF-Token', get_query_parameter(queryParams, ['csrftoken']))
                if session.csrf_token != token:
                    raise HTTPAPIError('Invalid CSRF token', apache.HTTP_FORBIDDEN)
            aw = AccessWrapper()
            if not onlyPublic:
                aw.setUser(session.getUser())
            userPrefix = 'user-' + session.getUser().getId() + '_'
            cacheKey = userPrefix + normalizeQuery(path, query,
                                                   remove=('nc', 'nocache', 'ca', 'cookieauth', 'oa', 'onlyauthed',
                                                           'csrftoken'))

        # Bail out if the user requires authentication but is not authenticated
        if onlyAuthed and not aw.getUser():
            raise HTTPAPIError('Not authenticated', apache.HTTP_FORBIDDEN)

        obj = None
        addToCache = not hook.NO_CACHE
        cache = GenericCache('HTTPAPI')
        cacheKey = RE_REMOVE_EXTENSION.sub('', cacheKey)
        if not noCache:
            obj = cache.get(cacheKey)
            if obj is not None:
                result, extra, ts, complete, typeMap = obj
                addToCache = False
        if result is None:
            # Perform the actual exporting
            res = hook(aw, req)
            if isinstance(res, tuple) and len(res) == 4:
                result, extra, complete, typeMap = res
            else:
                result, extra, complete, typeMap = res, {}, True, {}
        if result is not None and addToCache:
            ttl = HelperMaKaCInfo.getMaKaCInfoInstance().getAPICacheTTL()
            cache.set(cacheKey, (result, extra, ts, complete, typeMap), ttl)
    except HTTPAPIError, e:
        error = e
        if e.getCode():
            req.status = e.getCode()
            if req.status == apache.HTTP_METHOD_NOT_ALLOWED:
                req.headers_out['Allow'] = 'GET' if req.method == 'POST' else 'POST'
Ejemplo n.º 3
0
                else:
                    break
        else:
            # No need to commit stuff if we didn't use an API key
            # (nothing was written)
            if minfo.getRoomBookingModuleActive():
                Factory.getDALManager().rollback()
                Factory.getDALManager().disconnect()
            dbi.endRequest(False)

        # Log successful POST api requests
        if error is None and req.method == 'POST':
            logger.info('API request: %s?%s' % (path, query))

        serializer = Serializer.create(dformat, pretty=pretty, typeMap=typeMap,
                                       **remove_lists(queryParams))
        if error:
            if not serializer.schemaless:
                # if our serializer has a specific schema (HTML, ICAL, etc...)
                # use JSON, since it is universal
                serializer = Serializer.create('json')

            result = fossilize(error)
        else:
            if serializer.encapsulate:
                result = fossilize(HTTPAPIResult(result, path, query, ts, complete, extra), IHTTPAPIExportResultFossil)
                del result['_fossil']

        try:
            data = serializer(result)
            serializer.set_headers(req)
Ejemplo n.º 4
0
def handler(req, **params):
    ContextManager.destroy()
    logger = Logger.get('httpapi')
    path, query = req.URLFields['PATH_INFO'], req.URLFields['QUERY_STRING']
    if req.method == 'POST':
        # Convert POST data to a query string
        queryParams = dict(req.form)
        for key, value in queryParams.iteritems():
            queryParams[key] = [str(value)]
        query = urllib.urlencode(remove_lists(queryParams))
    else:
        # Parse the actual query string
        queryParams = parse_qs(query)

    dbi = DBMgr.getInstance()
    dbi.startRequest()
    minfo = HelperMaKaCInfo.getMaKaCInfoInstance()
    if minfo.getRoomBookingModuleActive():
        Factory.getDALManager().connect()

    mode = path.split('/')[1]

    apiKey = get_query_parameter(queryParams, ['ak', 'apikey'], None)
    signature = get_query_parameter(queryParams, ['signature'])
    timestamp = get_query_parameter(queryParams, ['timestamp'],
                                    0,
                                    integer=True)
    no_cache = get_query_parameter(queryParams, ['nc', 'nocache'],
                                   'no') == 'yes'
    pretty = get_query_parameter(queryParams, ['p', 'pretty'], 'no') == 'yes'
    onlyPublic = get_query_parameter(queryParams, ['op', 'onlypublic'],
                                     'no') == 'yes'

    # Disable caching if we are not exporting
    if mode != 'export':
        no_cache = True

    # Get our handler function and its argument and response type
    func, dformat = HTTPAPIHook.parseRequest(path, queryParams)
    if func is None or dformat is None:
        raise apache.SERVER_RETURN, apache.HTTP_NOT_FOUND

    ak = error = result = None
    ts = int(time.time())
    typeMap = {}
    try:
        # Validate the API key (and its signature)
        ak, enforceOnlyPublic = checkAK(apiKey, signature, timestamp, path,
                                        query)
        if enforceOnlyPublic:
            onlyPublic = True
        # Create an access wrapper for the API key's user
        aw = buildAW(ak, req, onlyPublic)
        # Get rid of API key in cache key if we did not impersonate a user
        if ak and aw.getUser() is None:
            cache_key = normalizeQuery(path,
                                       query,
                                       remove=('ak', 'apiKey', 'signature',
                                               'timestamp', 'nc', 'nocache'))
        else:
            cache_key = normalizeQuery(path,
                                       query,
                                       remove=('signature', 'timestamp', 'nc',
                                               'nocache'))
            if signature:
                # in case the request was signed, store the result under a different key
                cache_key = 'signed_' + cache_key

        obj = None
        addToCache = True
        cache = GenericCache('HTTPAPI')
        cache_key = RE_REMOVE_EXTENSION.sub('', cache_key)
        if not no_cache:
            obj = cache.get(cache_key)
            if obj is not None:
                result, extra, ts, complete, typeMap = obj
                addToCache = False
        if result is None:
            # Perform the actual exporting
            res = func(aw, req)
            if isinstance(res, tuple) and len(res) == 4:
                result, extra, complete, typeMap = res
            else:
                result, extra, complete, typeMap = res, {}, True, {}
        if result is not None and addToCache:
            ttl = HelperMaKaCInfo.getMaKaCInfoInstance().getAPICacheTTL()
            cache.set(cache_key, (result, extra, ts, complete, typeMap), ttl)
    except HTTPAPIError, e:
        error = e
        if e.getCode():
            req.status = e.getCode()
            if req.status == apache.HTTP_METHOD_NOT_ALLOWED:
                req.headers_out[
                    'Allow'] = 'GET' if req.method == 'POST' else 'POST'
Ejemplo n.º 5
0
def handler(req, **params):
    ContextManager.destroy()
    logger = Logger.get("httpapi")
    path, query = req.URLFields["PATH_INFO"], req.URLFields["QUERY_STRING"]
    if req.method == "POST":
        # Convert POST data to a query string
        queryParams = dict(req.form)
        for key, value in queryParams.iteritems():
            queryParams[key] = [str(value)]
        query = urllib.urlencode(remove_lists(queryParams))
    else:
        # Parse the actual query string
        queryParams = parse_qs(query)

    dbi = DBMgr.getInstance()
    dbi.startRequest()
    minfo = HelperMaKaCInfo.getMaKaCInfoInstance()
    if minfo.getRoomBookingModuleActive():
        Factory.getDALManager().connect()

    apiKey = get_query_parameter(queryParams, ["ak", "apikey"], None)
    cookieAuth = get_query_parameter(queryParams, ["ca", "cookieauth"], "no") == "yes"
    signature = get_query_parameter(queryParams, ["signature"])
    timestamp = get_query_parameter(queryParams, ["timestamp"], 0, integer=True)
    noCache = get_query_parameter(queryParams, ["nc", "nocache"], "no") == "yes"
    pretty = get_query_parameter(queryParams, ["p", "pretty"], "no") == "yes"
    onlyPublic = get_query_parameter(queryParams, ["op", "onlypublic"], "no") == "yes"
    onlyAuthed = get_query_parameter(queryParams, ["oa", "onlyauthed"], "no") == "yes"

    # Get our handler function and its argument and response type
    hook, dformat = HTTPAPIHook.parseRequest(path, queryParams)
    if hook is None or dformat is None:
        raise apache.SERVER_RETURN, apache.HTTP_NOT_FOUND

    # Disable caching if we are not just retrieving data (or the hook requires it)
    if req.method == "POST" or hook.NO_CACHE:
        noCache = True

    ak = error = result = None
    ts = int(time.time())
    typeMap = {}
    try:
        sessionUser = getSessionForReq(req).getUser() if cookieAuth else None
        if apiKey or not sessionUser:
            # Validate the API key (and its signature)
            ak, enforceOnlyPublic = checkAK(apiKey, signature, timestamp, path, query)
            if enforceOnlyPublic:
                onlyPublic = True
            # Create an access wrapper for the API key's user
            aw = buildAW(ak, req, onlyPublic)
            # Get rid of API key in cache key if we did not impersonate a user
            if ak and aw.getUser() is None:
                cacheKey = normalizeQuery(
                    path, query, remove=("ak", "apiKey", "signature", "timestamp", "nc", "nocache", "oa", "onlyauthed")
                )
            else:
                cacheKey = normalizeQuery(
                    path, query, remove=("signature", "timestamp", "nc", "nocache", "oa", "onlyauthed")
                )
                if signature:
                    # in case the request was signed, store the result under a different key
                    cacheKey = "signed_" + cacheKey
        else:
            # We authenticated using a session cookie.
            # Reject POST for security reasons (CSRF)
            if req.method == "POST":
                raise HTTPAPIError("Cannot POST when using cookie authentication", apache.HTTP_FORBIDDEN)
            aw = AccessWrapper()
            if not onlyPublic:
                aw.setUser(sessionUser)
            userPrefix = "user-" + sessionUser.getId() + "_"
            cacheKey = userPrefix + normalizeQuery(
                path, query, remove=("nc", "nocache", "ca", "cookieauth", "oa", "onlyauthed")
            )

        # Bail out if the user requires authentication but is not authenticated
        if onlyAuthed and not aw.getUser():
            raise HTTPAPIError("Not authenticated", apache.HTTP_FORBIDDEN)

        obj = None
        addToCache = not hook.NO_CACHE
        cache = GenericCache("HTTPAPI")
        cacheKey = RE_REMOVE_EXTENSION.sub("", cacheKey)
        if not noCache:
            obj = cache.get(cacheKey)
            if obj is not None:
                result, extra, ts, complete, typeMap = obj
                addToCache = False
        if result is None:
            # Perform the actual exporting
            res = hook(aw, req)
            if isinstance(res, tuple) and len(res) == 4:
                result, extra, complete, typeMap = res
            else:
                result, extra, complete, typeMap = res, {}, True, {}
        if result is not None and addToCache:
            ttl = HelperMaKaCInfo.getMaKaCInfoInstance().getAPICacheTTL()
            cache.set(cacheKey, (result, extra, ts, complete, typeMap), ttl)
    except HTTPAPIError, e:
        error = e
        if e.getCode():
            req.status = e.getCode()
            if req.status == apache.HTTP_METHOD_NOT_ALLOWED:
                req.headers_out["Allow"] = "GET" if req.method == "POST" else "POST"
Ejemplo n.º 6
0
                    pass  # retry
                else:
                    break
        else:
            # No need to commit stuff if we didn't use an API key
            # (nothing was written)
            if minfo.getRoomBookingModuleActive():
                Factory.getDALManager().rollback()
                Factory.getDALManager().disconnect()
            dbi.endRequest(False)

        # Log successful POST api requests
        if error is None and req.method == "POST":
            logger.info("API request: %s?%s" % (path, query))

        serializer = Serializer.create(dformat, pretty=pretty, typeMap=typeMap, **remove_lists(queryParams))
        if error:
            if not serializer.schemaless:
                # if our serializer has a specific schema (HTML, ICAL, etc...)
                # use JSON, since it is universal
                serializer = Serializer.create("json")

            result = fossilize(error)
        else:
            if serializer.encapsulate:
                result = fossilize(HTTPAPIResult(result, path, query, ts, complete, extra), IHTTPAPIExportResultFossil)
                del result["_fossil"]

        try:
            data = serializer(result)
            serializer.set_headers(req)
Ejemplo n.º 7
0
def handler(req, **params):
    ContextManager.destroy()
    logger = Logger.get('httpapi')
    path, query = req.URLFields['PATH_INFO'], req.URLFields['QUERY_STRING']
    if req.method == 'POST':
        # Convert POST data to a query string
        queryParams = dict(req.form)
        for key, value in queryParams.iteritems():
            queryParams[key] = [str(value)]
        query = urllib.urlencode(remove_lists(queryParams))
    else:
        # Parse the actual query string
        queryParams = parse_qs(query)

    dbi = DBMgr.getInstance()
    dbi.startRequest()
    minfo = HelperMaKaCInfo.getMaKaCInfoInstance()
    if minfo.getRoomBookingModuleActive():
        Factory.getDALManager().connect()

    mode = path.split('/')[1]

    apiKey = get_query_parameter(queryParams, ['ak', 'apikey'], None)
    signature = get_query_parameter(queryParams, ['signature'])
    timestamp = get_query_parameter(queryParams, ['timestamp'], 0, integer=True)
    no_cache = get_query_parameter(queryParams, ['nc', 'nocache'], 'no') == 'yes'
    pretty = get_query_parameter(queryParams, ['p', 'pretty'], 'no') == 'yes'
    onlyPublic = get_query_parameter(queryParams, ['op', 'onlypublic'], 'no') == 'yes'

    # Disable caching if we are not exporting
    if mode != 'export':
        no_cache = True

    # Get our handler function and its argument and response type
    func, dformat = HTTPAPIHook.parseRequest(path, queryParams)
    if func is None or dformat is None:
        raise apache.SERVER_RETURN, apache.HTTP_NOT_FOUND

    ak = error = result = None
    ts = int(time.time())
    typeMap = {}
    try:
        # Validate the API key (and its signature)
        ak, enforceOnlyPublic = checkAK(apiKey, signature, timestamp, path, query)
        if enforceOnlyPublic:
            onlyPublic = True
        # Create an access wrapper for the API key's user
        aw = buildAW(ak, req, onlyPublic)
        # Get rid of API key in cache key if we did not impersonate a user
        if ak and aw.getUser() is None:
            cache_key = normalizeQuery(path, query, remove=('ak', 'apiKey', 'signature', 'timestamp', 'nc', 'nocache'))
        else:
            cache_key = normalizeQuery(path, query, remove=('signature', 'timestamp', 'nc', 'nocache'))
            if signature:
                # in case the request was signed, store the result under a different key
                cache_key = 'signed_' + cache_key

        obj = None
        addToCache = True
        cache = GenericCache('HTTPAPI')
        cache_key = RE_REMOVE_EXTENSION.sub('', cache_key)
        if not no_cache:
            obj = cache.get(cache_key)
            if obj is not None:
                result, extra, ts, complete, typeMap = obj
                addToCache = False
        if result is None:
            # Perform the actual exporting
            res = func(aw, req)
            if isinstance(res, tuple) and len(res) == 4:
                result, extra, complete, typeMap = res
            else:
                result, extra, complete, typeMap = res, {}, True, {}
        if result is not None and addToCache:
            ttl = HelperMaKaCInfo.getMaKaCInfoInstance().getAPICacheTTL()
            cache.set(cache_key, (result, extra, ts, complete, typeMap), ttl)
    except HTTPAPIError, e:
        error = e
        if e.getCode():
            req.status = e.getCode()
            if req.status == apache.HTTP_METHOD_NOT_ALLOWED:
                req.headers_out['Allow'] = 'GET' if req.method == 'POST' else 'POST'