def _run(self):
        Logger.get('OfflineEventGeneratorTask').info(
            "Started generation of the offline website for task: %s" %
            self._task.id)
        setLocale(self._task.avatar.getLang())
        self._rh = RHCustomizable()
        self._aw = self._rh._aw = AccessWrapper()
        self._rh._conf = self._rh._target = self._task.conference

        ContextManager.set('currentRH', self._rh)
        ContextManager.set('offlineMode', True)

        # Get event type
        wf = self._rh.getWebFactory()
        if wf:
            eventType = wf.getId()
        else:
            eventType = "conference"

        try:
            websiteZipFile = OfflineEvent(self._rh, self._rh._conf,
                                          eventType).create()
        except Exception, e:
            Logger.get('OfflineEventGeneratorTask').exception(
                "Generation of the offline website for task %s failed \
                with message error: %s" % (self._task.id, e))
            self._task.status = "Failed"
            return
Example #2
0
 def _setMailText(self):
     text = self.text
     if self.note:
         text = text + "Note: %s" % self.note
     if self.confSumary:
         #try:
         from MaKaC.common.output import outputGenerator
         from MaKaC.accessControl import AdminList, AccessWrapper
         import MaKaC.webinterface.urlHandlers as urlHandlers
         admin = AdminList().getInstance().getList()[0]
         aw = AccessWrapper()
         aw.setUser(admin)
         path = Config.getInstance().getStylesheetsDir()
         if os.path.exists("%s/text.xsl" % path):
             stylepath = "%s/text.xsl" % path
         outGen = outputGenerator(aw)
         vars = { \
                 "modifyURL": urlHandlers.UHConferenceModification.getURL( self.conf ), \
                 "sessionModifyURLGen": urlHandlers.UHSessionModification.getURL, \
                 "contribModifyURLGen": urlHandlers.UHContributionModification.getURL, \
                 "subContribModifyURLGen":  urlHandlers.UHSubContribModification.getURL, \
                 "materialURLGen": urlHandlers.UHMaterialDisplay.getURL, \
                 "resourceURLGen": urlHandlers.UHFileAccess.getURL }
         confText = outGen.getOutput(self.conf, stylepath, vars)
         text += "\n\n\n" + confText
     #except:
     #    text += "\n\n\nSorry could not embed text version of the agenda..."
     self.mail.setText(text)
Example #3
0
def get_suggested_categories(user):
    """Gets the suggested categories of a user for the dashboard"""
    from MaKaC.conference import CategoryManager

    if not redis_write_client:
        return []
    related = user.favorite_categories | user.get_linked_objects('category', 'manager')
    res = []
    for id_, score in suggestions.get_suggestions(user, 'category').iteritems():
        try:
            categ = CategoryManager().getById(id_)
        except KeyError:
            suggestions.unsuggest(user, 'category', id_)
            continue
        if not categ or categ.isSuggestionsDisabled() or categ in related:
            continue
        if any(p.isSuggestionsDisabled() for p in categ.iterParents()):
            continue
        if not categ.canAccess(AccessWrapper(user.as_avatar)):
            continue
        res.append({
            'score': score,
            'categ': categ,
            'path': truncate_path(categ.getCategoryPathTitles()[:-1], chars=50)
        })
    return res
Example #4
0
 def can_access(self, user, allow_admin=True):
     if not allow_admin:
         raise NotImplementedError(
             'can_access(..., allow_admin=False) is unsupported until ACLs are migrated'
         )
     from MaKaC.accessControl import AccessWrapper
     return self.as_legacy.canAccess(
         AccessWrapper(user.as_avatar if user else None))
Example #5
0
 def __init__(self):
     self.closed = False
     self.xml_generator = XMLGen()
     self.xml_generator.initXml()
     self.xml_generator.openTag(b'collection', [[b'xmlns', b'http://www.loc.gov/MARC21/slim']])
     # This is horrible. but refactoring all the code in the indico core would be just as bad.
     aw = AccessWrapper()
     aw.setUser(User.find_first(is_admin=True).as_avatar)
     self.output_generator = outputGenerator(aw, self.xml_generator)
Example #6
0
def iter_interesting_events(avatar, data):
    idx = IndexesHolder().getById('categoryDateAll')
    now_local = utc2server(nowutc(), False)
    aw = AccessWrapper()
    aw.setUser(avatar)
    for event in _unique_events(
            idx.iterateObjectsIn('0', now_local,
                                 now_local + timedelta(weeks=24))):
        if _is_event_interesting(avatar, event, data) and event.canAccess(aw):
            yield event
Example #7
0
 def _process_PUT(self):
     category = CategoryManager().getById(request.view_args['category_id'])
     if category not in self.user.favorite_categories:
         if not category.canAccess(AccessWrapper(self.user.as_avatar)):
             raise Forbidden()
         self.user.favorite_categories.add(category)
         if redis_write_client:
             suggestions.unignore(self.user, 'category', category.getId())
             suggestions.unsuggest(self.user, 'category', category.getId())
     return jsonify(success=True)
Example #8
0
def buildAW(ak, onlyPublic=False):
    aw = AccessWrapper()
    if ak and not onlyPublic:
        # If we have an authenticated request, require HTTPS
        # Dirty hack: Google calendar converts HTTP API requests from https to http
        # Therefore, not working with Indico setup (requiring https for HTTP API authenticated)
        if not request.is_secure and api_settings.get(
                'require_https') and request.user_agent.browser != 'google':
            raise HTTPAPIError('HTTPS is required', 403)
        aw.setUser(ak.user.as_avatar)
    return aw
Example #9
0
def buildAW(ak, req, onlyPublic=False):
    aw = AccessWrapper()
    if ak and not onlyPublic:
        # If we have an authenticated request, require HTTPS
        minfo = HelperMaKaCInfo.getMaKaCInfoInstance()
        # Dirty hack: Google calendar converts HTTP API requests from https to http
        # Therefore, not working with Indico setup (requiring https for HTTP API authenticated)
        if not req.is_https() and minfo.isAPIHTTPSRequired() and req.get_user_agent().find("Googlebot") == -1:
            raise HTTPAPIError('HTTPS is required', apache.HTTP_FORBIDDEN)
        aw.setUser(ak.getUser())
    return aw
Example #10
0
    def can_view(self, user):
        """Checks if the user can see the folder.

        This does not mean the user can actually access its contents.
        It just determines if it is visible to him or not.
        """
        if not self.linked_object.canView(
                AccessWrapper(user.as_avatar if user else None)):
            return False
        return self.is_always_visible or super(AttachmentFolder,
                                               self).can_access(user)
Example #11
0
 def __init__(self):
     self._responseUtil = ResponseUtil()
     self._requestStarted = False
     self._aw = AccessWrapper(
     )  # Fill in the aw instance with the current information
     self._target = None
     self._reqParams = {}
     self._startTime = None
     self._endTime = None
     self._tempFilesToDelete = []
     self._redisPipeline = None
     self._doProcess = True  # Flag which indicates whether the RH process
Example #12
0
def buildAW(ak, onlyPublic=False):
    aw = AccessWrapper()
    aw.setIP(str(request.remote_addr))
    if ak and not onlyPublic:
        # If we have an authenticated request, require HTTPS
        minfo = HelperMaKaCInfo.getMaKaCInfoInstance()
        # Dirty hack: Google calendar converts HTTP API requests from https to http
        # Therefore, not working with Indico setup (requiring https for HTTP API authenticated)
        if not request.is_secure and minfo.isAPIHTTPSRequired(
        ) and request.user_agent.browser != 'google':
            raise HTTPAPIError('HTTPS is required', 403)
        aw.setUser(ak.getUser())
    return aw
Example #13
0
def buildCache(ids):
    i = 1
    for id in ids:
        DBMgr.getInstance().startRequest()
        try:
            conf = ConferenceHolder().getById(id)
        except:
            print "conf %s not found"
            continue
        print i, ":", conf.getId()
        og = outputGenerator(AccessWrapper())
        x = og.confToXML(conf, 1, 1, 1, overrideCache=True)
        y = og.confToXMLMarc21(conf, 1, 1, 1, overrideCache=True)
        i += 1
        DBMgr.getInstance().endRequest()
Example #14
0
 def __init__(self, params):
     if not self.UNICODE_PARAMS:
         params = unicode_struct_to_utf8(params)
     self._reqParams = self._params = params
     self._requestStarted = False
     # Fill in the aw instance with the current information
     self._aw = AccessWrapper()
     self._aw.setUser(session.avatar)
     self._target = None
     self._startTime = None
     self._tohttps = request.is_secure
     self._endTime = None
     self._doProcess = True  #Flag which indicates whether the RH process
     #   must be carried out; this is useful for
     #   the checkProtection methods
     self._tempFilesToDelete = []
     self._redisPipeline = None
Example #15
0
    def __init__(self, req=None):
        """Constructor. Initialises the rh setting up basic attributes so it is
            able to process the request.

            Parameters:
                req - OBSOLETE, MUST BE NONE
        """
        RequestHandlerBase.__init__(self, req)
        self._responseUtil = ResponseUtil()
        self._requestStarted = False
        self._aw = AccessWrapper(
        )  # Fill in the aw instance with the current information
        self._target = None
        self._reqParams = {}
        self._startTime = None
        self._endTime = None
        self._tempFilesToDelete = []
        self._redisPipeline = None
        self._doProcess = True  # Flag which indicates whether the RH process
Example #16
0
    def __init__(self, req):
        """Constructor. Initialises the rh setting up basic attributes so it is
            able to process the request.

            Parameters:
                req - (mod_python.Request) mod_python request received for the
                    current rh.
        """
        RequestHandlerBase.__init__(self, req)
        self._requestStarted = False
        self._websession = None
        self._aw = AccessWrapper(
        )  #Fill in the aw instance with the current information
        self._target = None
        self._reqParams = {}
        self._startTime = None
        self._endTime = None
        self._tempFilesToDelete = []
        self._doProcess = True  #Flag which indicates whether the RH process
Example #17
0
def buildCache(ids):
    i = 1
    for id in ids:
        DBMgr.getInstance().startRequest()
        try:
            conf = ConferenceHolder().getById(id)
        except:
            print "conf %s not found"
            continue
        j = 1
        for cont in conf.getContributionList():
            print "conf %d:%s - contrib %d:%s"%(i, conf.getId(), j, cont.getId())
            og = outputGenerator(AccessWrapper())
            x = og.contribToXMLMarc21(cont, 1, overrideCache=True)
            for subCont in cont.getSubContributionList():
                print "conf %d:%s - contrib %d:%s - subContrib:%s"%(i, conf.getId(), j, cont.getId(), subCont.getId())
                y = og.subContribToXMLMarc21(subCont, 1, overrideCache=True)
            j += 1
        i += 1
        DBMgr.getInstance().endRequest()
Example #18
0
 def __init__(self, params, remoteHost, session):
     """
     Constructor.  Initializes provate variables
     @param req: HTTP Request provided by the previous layer
     """
     self._params = params
     self._requestStarted = False
     self._websession = session
     # Fill in the aw instance with the current information
     self._aw = AccessWrapper()
     self._aw.setIP(remoteHost)
     self._aw.setSession(session)
     self._aw.setUser(session.getUser())
     self._target = None
     self._startTime = None
     self._endTime = None
     self._doProcess = True  #Flag which indicates whether the RH process
     #   must be carried out; this is useful for
     #   the checkProtection methods
     self._tempFilesToDelete = []
Example #19
0
def build_static_site(static_site):
    static_site.state = StaticSiteState.running
    db.session.commit()
    try:
        logger.info('Building static site: %s', static_site)
        session.lang = static_site.creator.settings.get('lang')
        rh = RHCustomizable()
        rh._aw = AccessWrapper()
        rh._conf = rh._target = static_site.event_new.as_legacy

        g.rh = rh
        ContextManager.set('currentRH', rh)
        g.static_site = True

        # Get event type
        wf = rh.getWebFactory()
        event_type = wf.getId() if wf else 'conference'

        zip_file_path = OfflineEvent(rh, rh._conf,
                                     event_type).create(static_site.id)

        static_site.path = zip_file_path
        static_site.state = StaticSiteState.success
        db.session.commit()

        logger.info('Building static site successful: %s', static_site)
        g.static_site = False
        ContextManager.set('currentRH', None)
        notify_static_site_success(static_site)
    except Exception:
        logger.exception('Building static site failed: %s', static_site)
        static_site.state = StaticSiteState.failed
        db.session.commit()
        raise
    finally:
        g.static_site = False
        ContextManager.set('currentRH', None)
Example #20
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'
Example #21
0
def handler(prefix, path):
    path = posixpath.join('/', prefix, path)
    ContextManager.destroy()
    clearCache()  # init fossil cache
    logger = Logger.get('httpapi')
    if request.method == 'POST':
        # Convert POST data to a query string
        queryParams = [(key, [x.encode('utf-8') for x in values])
                       for key, values in request.form.iterlists()]
        query = urllib.urlencode(queryParams, doseq=1)
        # we only need/keep multiple values so we can properly validate the signature.
        # the legacy code below expects a dict with just the first value.
        # if you write a new api endpoint that needs multiple values get them from
        # ``request.values.getlist()`` directly
        queryParams = {key: values[0] for key, values in queryParams}
    else:
        # Parse the actual query string
        queryParams = dict((key, value.encode('utf-8'))
                           for key, value in request.args.iteritems())
        query = request.query_string

    dbi = DBMgr.getInstance()
    dbi.startRequest()

    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'
    scope = 'read:legacy_api' if request.method == 'GET' else 'write:legacy_api'
    try:
        oauth_valid, oauth_request = oauth.verify_request([scope])
        if not oauth_valid and oauth_request and oauth_request.error_message != 'Bearer token not found.':
            raise BadRequest('OAuth error: {}'.format(
                oauth_request.error_message))
        elif g.get(
                'received_oauth_token'
        ) and oauth_request.error_message == 'Bearer token not found.':
            raise BadRequest('OAuth error: Invalid token')
    except ValueError:
        # XXX: Dirty hack to workaround a bug in flask-oauthlib that causes it
        #      not to properly urlencode request query strings
        #      Related issue (https://github.com/lepture/flask-oauthlib/issues/213)
        oauth_valid = False

    # 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 NotFound

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

    ak = error = result = None
    ts = int(time.time())
    typeMap = {}
    responseUtil = ResponseUtil()
    is_response = False
    try:
        used_session = None
        if cookieAuth:
            used_session = session
            if not used_session.user:  # ignore guest sessions
                used_session = None

        if apiKey or oauth_valid or not used_session:
            if not oauth_valid:
                # 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, onlyPublic)
            else:  # Access Token (OAuth)
                at = load_token(oauth_request.access_token.access_token)
                aw = buildAW(at, 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 = request.headers.get(
                    'X-CSRF-Token',
                    get_query_parameter(queryParams, ['csrftoken']))
                if used_session.csrf_protected and used_session.csrf_token != token:
                    raise HTTPAPIError('Invalid CSRF token', 403)
            aw = AccessWrapper()
            if not onlyPublic:
                aw.setUser(used_session.avatar)
            userPrefix = 'user-{}_'.format(used_session.user.id)
            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', 403)

        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:
            ContextManager.set("currentAW", aw)
            # Perform the actual exporting
            res = hook(aw)
            if isinstance(res, current_app.response_class):
                addToCache = False
                is_response = True
                result, extra, complete, typeMap = res, {}, True, {}
            elif 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 = api_settings.get('cache_ttl')
            if ttl > 0:
                cache.set(cacheKey, (result, extra, ts, complete, typeMap),
                          ttl)
    except HTTPAPIError, e:
        error = e
        if e.getCode():
            responseUtil.status = e.getCode()
            if responseUtil.status == 405:
                responseUtil.headers[
                    'Allow'] = 'GET' if request.method == 'POST' else 'POST'
Example #22
0
 def _checkProtection(self):
     RHNoteBase._checkProtection(self)
     if not self.object.canAccess(AccessWrapper(session.avatar)):
         raise Forbidden
Example #23
0
    def can_access(self, user, allow_admin=True):
        """Checks if the user can access the object.

        :param user: The :class:`.User` to check. May be None if the
                     user is not logged in.
        :param allow_admin: If admin users should always have access
        """

        # Trigger signals for protection overrides
        rv = values_from_signal(signals.acl.can_access.send(
            type(self), obj=self, user=user, allow_admin=allow_admin),
                                single_value=True)
        if rv:
            # in case of contradictory results (shouldn't happen at all)
            # we stay on the safe side and deny access
            return all(rv)

        # Usually admins can access everything, so no need for checks
        if allow_admin and user and user.is_admin:
            return True

        if self.protection_mode == ProtectionMode.public:
            # if it's public we completely ignore the parent protection
            # this is quite ugly which is why it should only be allowed
            # in rare cases (e.g. events which might be in a protected
            # category but should be public nonetheless)
            return True
        elif self.protection_mode == ProtectionMode.protected:
            # if it's protected, we also ignore the parent protection
            # and only check our own ACL
            if user is None:
                return False
            elif any(user in entry.principal
                     for entry in iter_acl(self.acl_entries)):
                return True
            elif isinstance(self, ProtectionManagersMixin):
                return self.can_manage(user, allow_admin=allow_admin)
            else:
                return False
        elif self.protection_mode == ProtectionMode.inheriting:
            # if it's inheriting, we only check the parent protection
            # unless `inheriting_have_acl` is set, in which case we
            # might not need to check the parents at all
            if (self.inheriting_have_acl and user is not None
                    and any(user in entry.principal
                            for entry in iter_acl(self.acl_entries))):
                return True
            # the parent can be either an object inheriting from this
            # mixin or a legacy object with an AccessController
            parent = self.protection_parent
            if parent is None:
                # This should be the case for the top-level object,
                # i.e. the root category, which shouldn't allow
                # ProtectionMode.inheriting as it makes no sense.
                raise TypeError('protection_parent of {} is None'.format(self))
            elif hasattr(parent, 'can_access'):
                return parent.can_access(user, allow_admin=allow_admin)
            elif hasattr(parent, 'canAccess'):
                return parent.canAccess(
                    AccessWrapper(user.as_avatar if user else None))
            else:
                raise TypeError(
                    'protection_parent of {} is of invalid type {} ({})'.
                    format(self, type(parent), parent))
        else:
            # should never happen, but since this is a sensitive area
            # we better fail loudly if we have garbage
            raise ValueError('Invalid protection mode: {}'.format(
                self.protection_mode))
Example #24
0
def handler(prefix, path):
    path = posixpath.join('/', prefix, path)
    ContextManager.destroy()
    clearCache()  # init fossil cache
    logger = Logger.get('httpapi')
    if request.method == 'POST':
        # Convert POST data to a query string
        queryParams = dict((key, value.encode('utf-8'))
                           for key, value in request.form.iteritems())
        query = urllib.urlencode(queryParams)
    else:
        # Parse the actual query string
        queryParams = dict((key, value.encode('utf-8'))
                           for key, value in request.args.iteritems())
        query = request.query_string

    dbi = DBMgr.getInstance()
    dbi.startRequest()

    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'
    oauthToken = 'oauth_token' in queryParams
    # Check if OAuth data is supplied in the Authorization header
    if not oauthToken and request.headers.get('Authorization') is not None:
        oauthToken = 'oauth_token' in request.headers.get('Authorization')

    # 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 NotFound

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

    ak = error = result = None
    ts = int(time.time())
    typeMap = {}
    responseUtil = ResponseUtil()
    try:
        used_session = None
        if cookieAuth:
            used_session = session
            if not used_session.avatar:  # ignore guest sessions
                used_session = None

        if apiKey or oauthToken or not used_session:
            if not oauthToken:
                # 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, onlyPublic)
            else:  # Access Token (OAuth)
                at = OAuthUtils.OAuthCheckAccessResource()
                aw = buildAW(at, 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 = request.headers.get(
                    'X-CSRF-Token',
                    get_query_parameter(queryParams, ['csrftoken']))
                if used_session.csrf_protected and used_session.csrf_token != token:
                    raise HTTPAPIError('Invalid CSRF token', 403)
            aw = AccessWrapper()
            if not onlyPublic:
                aw.setUser(used_session.avatar)
            userPrefix = 'user-' + used_session.avatar.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', 403)

        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:
            ContextManager.set("currentAW", aw)
            # Perform the actual exporting
            res = hook(aw)
            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 = api_settings.get('cache_ttl')
            cache.set(cacheKey, (result, extra, ts, complete, typeMap), ttl)
    except HTTPAPIError, e:
        error = e
        if e.getCode():
            responseUtil.status = e.getCode()
            if responseUtil.status == 405:
                responseUtil.headers[
                    'Allow'] = 'GET' if request.method == 'POST' else 'POST'
Example #25
0
 def _getAW(self):
     return AccessWrapper(session.avatar)