def principal_from_fossil(fossil, allow_pending=False, allow_groups=True, legacy=True, allow_missing_groups=False, allow_emails=False, allow_networks=False): from indico.modules.networks.models.networks import IPNetworkGroup from indico.modules.groups import GroupProxy from indico.modules.users import User type_ = fossil['_type'] id_ = fossil['id'] if type_ == 'Avatar': if isinstance(id_, int) or id_.isdigit(): # regular user user = User.get(int(id_)) elif allow_pending: data = GenericCache('pending_identities').get(id_) if not data: raise ValueError("Cannot find user '{}' in cache".format(id_)) data = {k: '' if v is None else v for (k, v) in data.items()} email = data['email'].lower() # check if there is not already a (pending) user with that e-mail # we need to check for non-pending users too since the search may # show a user from external results even though the email belongs # to an indico account in case some of the search criteria did not # match the indico account user = User.find_first(User.all_emails.contains(email), ~User.is_deleted) if not user: user = User(first_name=data.get('first_name') or '', last_name=data.get('last_name') or '', email=email, address=data.get('address', ''), phone=data.get('phone', ''), affiliation=data.get('affiliation', ''), is_pending=True) db.session.add(user) db.session.flush() else: raise ValueError("Id '{}' is not a number and allow_pending=False".format(id_)) if user is None: raise ValueError('User does not exist: {}'.format(id_)) return user.as_avatar if legacy else user elif allow_emails and type_ == 'Email': return EmailPrincipal(id_) elif allow_networks and type_ == 'IPNetworkGroup': group = IPNetworkGroup.get(int(id_)) if group is None: raise ValueError('IP network group does not exist: {}'.format(id_)) return group elif allow_groups and type_ in {'LocalGroupWrapper', 'LocalGroup'}: group = GroupProxy(int(id_)) if group.group is None: raise ValueError('Local group does not exist: {}'.format(id_)) return group.as_legacy_group if legacy else group elif allow_groups and type_ in {'LDAPGroupWrapper', 'MultipassGroup'}: provider = fossil['provider'] group = GroupProxy(id_, provider) if group.group is None and not allow_missing_groups: raise ValueError('Multipass group does not exist: {}:{}'.format(provider, id_)) return group.as_legacy_group if legacy else group else: raise ValueError('Unexpected fossil type: {}'.format(type_))
def principal_from_fossil(fossil, allow_pending=False, allow_groups=True, legacy=True, allow_missing_groups=False, allow_emails=False): """Gets a GroupWrapper or AvatarUserWrapper from a fossil""" from indico.modules.groups import GroupProxy from indico.modules.users import User type_ = fossil['_type'] id_ = fossil['id'] if type_ == 'Avatar': if isinstance(id_, int) or id_.isdigit(): # regular user user = User.get(int(id_)) elif allow_pending: data = GenericCache('pending_identities').get(id_) if not data: raise ValueError("Cannot find user '{}' in cache".format(id_)) data = {k: '' if v is None else v for (k, v) in data.items()} email = data['email'].lower() # check if there is not already a pending user with that e-mail user = User.find_first(email=email, is_pending=True) if not user: user = User(first_name=data.get('first_name') or '', last_name=data.get('last_name') or '', email=email, address=data.get('address', ''), phone=data.get('phone', ''), affiliation=data.get('affiliation', ''), is_pending=True) db.session.add(user) db.session.flush() else: raise ValueError( "Id '{}' is not a number and allow_pending=False".format(id_)) if user is None: raise ValueError('User does not exist: {}'.format(id_)) return user.as_avatar if legacy else user elif allow_emails and type_ == 'Email': return EmailPrincipal(id_) elif allow_groups and type_ in {'LocalGroupWrapper', 'LocalGroup'}: group = GroupProxy(int(id_)) if group.group is None: raise ValueError('Local group does not exist: {}'.format(id_)) return group.as_legacy_group if legacy else group elif allow_groups and type_ in {'LDAPGroupWrapper', 'MultipassGroup'}: provider = fossil['provider'] group = GroupProxy(id_, provider) if group.group is None and not allow_missing_groups: raise ValueError('Multipass group does not exist: {}:{}'.format( provider, id_)) return group.as_legacy_group if legacy else group else: raise ValueError('Unexpected fossil type: {}'.format(type_))
def principal_from_fossil(fossil, allow_pending=False, allow_groups=True, legacy=True, allow_missing_groups=False, allow_emails=False): """Gets a GroupWrapper or AvatarUserWrapper from a fossil""" from indico.modules.groups import GroupProxy from indico.modules.users import User type_ = fossil['_type'] id_ = fossil['id'] if type_ == 'Avatar': if isinstance(id_, int) or id_.isdigit(): # regular user user = User.get(int(id_)) elif allow_pending: data = GenericCache('pending_identities').get(id_) if not data: raise ValueError("Cannot find user '{}' in cache".format(id_)) data = {k: '' if v is None else v for (k, v) in data.items()} email = data['email'].lower() # check if there is not already a pending user with that e-mail user = User.find_first(email=email, is_pending=True) if not user: user = User(first_name=data.get('first_name') or '', last_name=data.get('last_name') or '', email=email, address=data.get('address', ''), phone=data.get('phone', ''), affiliation=data.get('affiliation', ''), is_pending=True) db.session.add(user) db.session.flush() else: raise ValueError("Id '{}' is not a number and allow_pending=False".format(id_)) if user is None: raise ValueError('User does not exist: {}'.format(id_)) return user.as_avatar if legacy else user elif allow_emails and type_ == 'Email': return EmailPrincipal(id_) elif allow_groups and type_ in {'LocalGroupWrapper', 'LocalGroup'}: group = GroupProxy(int(id_)) if group.group is None: raise ValueError('Local group does not exist: {}'.format(id_)) return group.as_legacy_group if legacy else group elif allow_groups and type_ in {'LDAPGroupWrapper', 'MultipassGroup'}: provider = fossil['provider'] group = GroupProxy(id_, provider) if group.group is None and not allow_missing_groups: raise ValueError('Multipass group does not exist: {}:{}'.format(provider, id_)) return group.as_legacy_group if legacy else group else: raise ValueError('Unexpected fossil type: {}'.format(type_))
class SudsCache(Cache): _instance = None def __init__(self, duration=DEFAULT_CACHE_TTL): self._cache = GenericCache("SudsCache") self._duration = duration def get(self, key): self._cache.get(key) def put(self, key, val): self._cache.set(key, val, self._duration) def purge(self, key): self._cache.delete(key)
def _send_confirmation(self, email): token_storage = GenericCache('confirm-email') data = {'email': email, 'user_id': self.user.id} token = make_unique_token(lambda t: not token_storage.get(t)) token_storage.set(token, data, 24 * 3600) GenericMailer.send(make_email(email, template=get_template_module('users/emails/verify_email.txt', user=self.user, email=email, token=token)))
class RHRoomBookingMapOfRoomsWidget(RHRoomBookingBase): def __init__(self, *args, **kwargs): RHRoomBookingBase.__init__(self, *args, **kwargs) self._cache = GenericCache('MapOfRooms') def _checkParams(self): RHRoomBookingBase._checkParams(self, request.args) self._room_id = request.args.get('roomID') def _process(self): key = str(sorted(dict(request.args, lang=session.lang, user=session.user.getId()).items())) html = self._cache.get(key) if not html: default_location = Location.default_location aspects = [a.to_serializable() for a in default_location.aspects] buildings = default_location.get_buildings() html = WPRoomBookingMapOfRoomsWidget(self, aspects=aspects, buildings=buildings, room_id=self._room_id, default_repeat='{}|0'.format(RepeatFrequency.NEVER), default_start_dt=datetime.combine(date.today(), Location.working_time_start), default_end_dt=datetime.combine(date.today(), Location.working_time_end), repeat_mapping=RepeatMapping.getMapping()).display() self._cache.set(key, html, 3600) return html
def _send_confirmation(self, email): token_storage = GenericCache('confirm-email') data = {'email': email, 'user_id': self.user.id} token = make_unique_token(lambda t: not token_storage.get(t)) token_storage.set(token, data, 24 * 3600) GenericMailer.send(make_email(email, template=get_template_module('users/emails/verify_email.txt', user=self.user, email=email, token=token)))
class RHRoomBookingMapOfRoomsWidget(RHRoomBookingBase): def __init__(self, *args, **kwargs): RHRoomBookingBase.__init__(self, *args, **kwargs) self._cache = GenericCache('MapOfRooms') def _checkParams(self): RHRoomBookingBase._checkParams(self, request.args) self._room_id = request.args.get('roomID') def _process(self): key = str( sorted( dict(request.args, lang=session.lang, user=session.user.getId()).items())) html = self._cache.get(key) if not html: default_location = Location.default_location aspects = [a.to_serializable() for a in default_location.aspects] buildings = default_location.get_buildings() html = WPRoomBookingMapOfRoomsWidget( self, aspects=aspects, buildings=buildings, room_id=self._room_id, default_repeat='{}|0'.format(RepeatFrequency.NEVER), default_start_dt=datetime.combine(date.today(), Location.working_time_start), default_end_dt=datetime.combine(date.today(), Location.working_time_end), repeat_mapping=RepeatMapping.mapping).display() self._cache.set(key, html, 3600) return html
def wrapper(*args, **kwargs): cache = GenericCache('task-locks') name = current_task.name if cache.get(name): Logger.get('celery').warning('Task {} is locked; not executing it'.format(name)) return cache.set(name, True) try: return f(*args, **kwargs) finally: cache.delete(name)
def wrapper(*args, **kwargs): cache = GenericCache('task-locks') name = current_task.name if cache.get(name): Logger.get('celery').warning('Task {} is locked; not executing it'.format(name)) return cache.set(name, True) try: return f(*args, **kwargs) finally: cache.delete(name)
def send_login_info(user, event=None): token_storage = GenericCache('resetpass') endpoint = 'event.confLogin-resetPassword' if event else 'user.signIn-resetPassword' idList = user.getIdentityList() logins = [] for id in idList: if not hasattr(id, 'setPassword'): config = Config.getInstance() extra_message = config.getAuthenticatorConfigById(id.getAuthenticatorTag()).get("ResetPasswordMessage") msg = _("Sorry, you are using an externally managed account (%s) to login into Indico.") % id.getLogin() if extra_message: msg += "\n" + extra_message logins.append({ 'tag': id.getAuthenticatorTag(), 'login': id.getLogin(), 'error': msg }) else: tag = id.getAuthenticatorTag() login = id.getLogin() data = {'tag': tag, 'login': login} token = str(uuid.uuid4()) while token_storage.get(token): token = str(uuid.uuid4()) token_storage.set(token, data, 6*3600) url = url_for(endpoint, event, token=token, _external=True, _secure=True) logins.append({ 'tag': tag, 'login': login, 'link': url }) if not logins: url = urlHandlers.UHUserDetails.getURL(user) text = _("Sorry, we did not find your login.\nPlease, create one here:\n%s") % url else: text = _("You can use the following links within the next six hours to reset your password.") for entry in logins: text += "\n\n==================\n" if 'link' in entry: text += _("Click below to reset your password for the %s login '%s':\n") % (entry['tag'], entry['login']) text += entry['link'] else: text += entry['error'] text += "\n==================\n" maildata = { "fromAddr": "Indico Mailer <%s>" % Config.getInstance().getNoReplyEmail(), "toList": [user.getEmail()], "subject": _("[%s] Login Information") % getSubjectIndicoTitle(), "body": text } GenericMailer.send(GenericNotification(maildata))
def _get_user_data(self): user_id = request.args.get('user') if user_id is None: return {} elif user_id.isdigit(): # existing indico user user = User.find_first(id=user_id, is_deleted=False) return {t.name: getattr(user, t.name, None) if user else '' for t in PersonalDataType} else: # non-indico user data = GenericCache('pending_identities').get(user_id, {}) return {t.name: data.get(t.name) for t in PersonalDataType}
def has_member(self, user): cache = GenericCache('group-membership') key = '{}:{}:{}'.format(self.provider, self.name, user.id) rv = cache.get(key) if rv is not None: return rv elif self.group is None: warn('Tried to check if {} is in invalid group {}'.format(user, self)) rv = False else: rv = any(x[1] in self.group for x in user.iter_identifiers(check_providers=True, providers={self.provider})) cache.set(key, rv, 1800) return rv
class SudsCache(Cache): _instance = None @classmethod def getInstance(cls, duration=None): if cls._instance is None: cls._instance = SudsCache(duration) return cls._instance def __init__(self, duration=None): self._cache = GenericCache("SudsCache") if duration is None: duration = 24 * 3600 # we put as default 1 day cache self._duration = duration def get(self, key): self._cache.get(key) def put(self, key, val): self._cache.set(key, val, self._duration) def purge(self, key): self._cache.delete(key)
def _get_user_data(self): user_id = request.args.get("user") if user_id is None: return {} elif user_id.isdigit(): # existing indico user user = User.find_first(id=user_id, is_deleted=False) user_data = {t.name: getattr(user, t.name, None) if user else "" for t in PersonalDataType} else: # non-indico user data = GenericCache("pending_identities").get(user_id, {}) user_data = {t.name: data.get(t.name) for t in PersonalDataType} user_data["title"] = get_title_uuid(self.regform, user_data["title"]) return user_data
class SudsCache(Cache): _instance = None @classmethod def getInstance(cls, duration=None): if cls._instance is None: cls._instance = SudsCache(duration) return cls._instance def __init__(self, duration=None): self._cache = GenericCache("SudsCache") if duration is None: duration = 24 * 3600 # we put as default 1 day cache self._duration = duration def get(self, key): self._cache.get(key) def put(self, key, val): self._cache.set(key, val, self._duration) def purge(self, key): self._cache.delete(key)
def _get_user_data(self): user_id = request.args.get('user') if user_id is None: return {} elif user_id.isdigit(): # existing indico user user = User.find_first(id=user_id, is_deleted=False) user_data = {t.name: getattr(user, t.name, None) if user else '' for t in PersonalDataType} else: # non-indico user data = GenericCache('pending_identities').get(user_id, {}) user_data = {t.name: data.get(t.name) for t in PersonalDataType} user_data['title'] = get_title_uuid(self.regform, user_data['title']) return user_data
def has_member(self, user): cache = GenericCache('group-membership') key = '{}:{}:{}'.format(self.provider, self.name, user.id) rv = cache.get(key) if rv is not None: return rv elif self.group is None: warn('Tried to check if {} is in invalid group {}'.format( user, self)) rv = False else: rv = any(x[1] in self.group for x in user.iter_identifiers(check_providers=True, providers={self.provider})) cache.set(key, rv, 1800) return rv
def get(cls, *args, **kwargs): """Create and return a serializable Report object, retrieved from cache if possible""" from indico_piwik.plugin import PiwikPlugin if not PiwikPlugin.settings.get('cache_enabled'): return cls(*args, **kwargs).to_serializable() cache = GenericCache('Piwik.Report') key = u'{}-{}-{}'.format(cls.__name__, args, kwargs) report = cache.get(key) if not report: report = cls(*args, **kwargs) cache.set(key, report, PiwikPlugin.settings.get('cache_ttl')) return report.to_serializable()
class CachedReport(object): """ This class acts as a wrapper for functions which return a report object, by decorating the get<report> methods with the memonize function in the BaseStatisticsReport object, the result is wrapped here and its age is compared with the TTL if in the cache, either returning said item or allowing the method to generate a new one. """ _config = StatisticsConfig() def __init__(self, function): self._function = function # Cache bucket per implementation plugin = function.__module__.split('.')[3] self._cache = GenericCache(plugin + 'StatisticsCache') def getReport(self, *args, **kwargs): """ Ascertain if live updating first, if so disregard and continue. """ ttl = self._config.getUpdateInterval() if not self._config.hasCacheEnabled(): return self._function(*args, **kwargs) keyParams = list(args) keyParams.extend([self._function.__module__, self._function.__name__]) key = self._generateKey(keyParams) resource = self._cache.get(key, None) if not resource: result = self._function(*args, **kwargs) self._cache.set(key, result, ttl) return result else: return resource def _generateKey(self, params): """ Generates a unique key for caching against the params given. """ return reduce(lambda x, y: str(x) + '-' + str(y), params)
class CachedReport(object): """ This class acts as a wrapper for functions which return a report object, by decorating the get<report> methods with the memonize function in the BaseStatisticsReport object, the result is wrapped here and its age is compared with the TTL if in the cache, either returning said item or allowing the method to generate a new one. """ _config = StatisticsConfig() def __init__(self, function): self._function = function # Cache bucket per implementation plugin = function.__module__.split('.')[3] self._cache = GenericCache(plugin + 'StatisticsCache') def getReport(self, *args, **kwargs): """ Ascertain if live updating first, if so disregard and continue. """ ttl = self._config.getUpdateInterval() if not self._config.hasCacheEnabled(): return self._function(*args, **kwargs) keyParams = list(args) keyParams.extend([self._function.__module__, self._function.__name__]) key = self._generateKey(keyParams) resource = self._cache.get(key, None) if not resource: result = self._function(*args, **kwargs) self._cache.set(key, result, ttl) return result else: return resource def _generateKey(self, params): """ Generates a unique key for caching against the params given. """ return reduce(lambda x, y: str(x) + '-' + str(y), params)
def _confirm_email_address(self, email, data_type): email = email.strip().lower() if not validMail(email): raise NoReportError(_("Invalid email address: {0}").format(email)) # Prevent adding the primary email as a secondary email if data_type == 'secondaryEmails' and email == self._avatar.getEmail(): raise NoReportError(_("{0} is already the primary email address " "and cannot be used as a secondary email address.").format(email)) # When setting a secondary email as primary, set it automatically and # re-index the user's emails without sending a confirmation email # (We assume the secondary emails are valid) if data_type == 'email' and email in self._avatar.getSecondaryEmails(): self._avatar.removeSecondaryEmail(email) self._avatar.setEmail(email, reindex=True) return False existing = AvatarHolder().match({'email': email}, searchInAuthenticators=False) if existing: if any(av for av in existing if av != self._avatar): raise NoReportError(_("The email address {0} is already used by another user.").format(email)) else: # The email is already set correctly for the user: Do nothing return False # New email address token_storage = GenericCache('confirm-email') data = {'email': email, 'data_type': data_type, 'uid': self._avatar.getId()} token = str(uuid.uuid4()) while token_storage.get(token): token = str(uuid.uuid4()) token_storage.set(token, data, 24 * 3600) url = url_for('user.confirm_email', token=token, _external=True, _secure=True) if data_type == 'email': body_format = _( "Dear {0},\n" "You requested to change your account's primary email address.\n" "Please open the link below within 24 hours to confirm and activate this email address:\n" "\n{1}\n\n" "--\n" "Indico" ) else: body_format = _( "Dear {0},\n" "You added this email address to your account's secondary emails list.\n" "Please open the link below within 24 hours to confirm and activate this email address:\n" "\n{1}\n\n" "--\n" "Indico" ) confirmation = { 'toList': [email], 'fromAddr': Config.getInstance().getSupportEmail(), 'subject': _("[Indico] Verify your email address"), 'body': body_format.format(self._avatar.getFirstName(), url) } # Send mail with template message and link GenericMailer.send(GenericNotification(confirmation)) return True
def principal_from_fossil(fossil, allow_pending=False, allow_groups=True, legacy=True, allow_missing_groups=False, allow_emails=False, allow_networks=False): from indico.modules.networks.models.networks import IPNetworkGroup from indico.modules.groups import GroupProxy from indico.modules.users import User type_ = fossil['_type'] id_ = fossil['id'] if type_ == 'Avatar': if isinstance(id_, int) or id_.isdigit(): # regular user user = User.get(int(id_)) elif allow_pending: data = GenericCache('pending_identities').get(id_) if not data: raise ValueError("Cannot find user '{}' in cache".format(id_)) data = {k: '' if v is None else v for (k, v) in data.items()} email = data['email'].lower() # check if there is not already a (pending) user with that e-mail # we need to check for non-pending users too since the search may # show a user from external results even though the email belongs # to an indico account in case some of the search criteria did not # match the indico account user = User.find_first(User.all_emails.contains(email), ~User.is_deleted) if not user: user = User(first_name=data.get('first_name') or '', last_name=data.get('last_name') or '', email=email, address=data.get('address', ''), phone=data.get('phone', ''), affiliation=data.get('affiliation', ''), is_pending=True) db.session.add(user) db.session.flush() else: raise ValueError( "Id '{}' is not a number and allow_pending=False".format(id_)) if user is None: raise ValueError('User does not exist: {}'.format(id_)) return user.as_avatar if legacy else user elif allow_emails and type_ == 'Email': return EmailPrincipal(id_) elif allow_networks and type_ == 'IPNetworkGroup': group = IPNetworkGroup.get(int(id_)) if group is None: raise ValueError('IP network group does not exist: {}'.format(id_)) return group elif allow_groups and type_ in {'LocalGroupWrapper', 'LocalGroup'}: group = GroupProxy(int(id_)) if group.group is None: raise ValueError('Local group does not exist: {}'.format(id_)) return group.as_legacy_group if legacy else group elif allow_groups and type_ in {'LDAPGroupWrapper', 'MultipassGroup'}: provider = fossil['provider'] group = GroupProxy(id_, provider) if group.group is None and not allow_missing_groups: raise ValueError('Multipass group does not exist: {}:{}'.format( provider, id_)) return group.as_legacy_group if legacy else group else: raise ValueError('Unexpected fossil type: {}'.format(type_))
def send_login_info(user, event=None): token_storage = GenericCache('resetpass') endpoint = 'event.confLogin-resetPassword' if event else 'user.signIn-resetPassword' idList = user.getIdentityList() logins = [] for id in idList: if not hasattr(id, 'setPassword'): config = Config.getInstance() extra_message = config.getAuthenticatorConfigById( id.getAuthenticatorTag()).get("ResetPasswordMessage") msg = _( "Sorry, you are using an externally managed account (%s) to login into Indico." ) % id.getLogin() if extra_message: msg += "\n" + extra_message logins.append({ 'tag': id.getAuthenticatorTag(), 'login': id.getLogin(), 'error': msg }) else: tag = id.getAuthenticatorTag() login = id.getLogin() data = {'tag': tag, 'login': login} token = str(uuid.uuid4()) while token_storage.get(token): token = str(uuid.uuid4()) token_storage.set(token, data, 6 * 3600) url = url_for(endpoint, event, token=token, _external=True, _secure=True) logins.append({'tag': tag, 'login': login, 'link': url}) if not logins: url = urlHandlers.UHUserDetails.getURL(user) text = _( "Sorry, we did not find your login.\nPlease, create one here:\n%s" ) % url else: text = _( "You can use the following links within the next six hours to reset your password." ) for entry in logins: text += "\n\n==================\n" if 'link' in entry: text += _( "Click below to reset your password for the %s login '%s':\n" ) % (entry['tag'], entry['login']) text += entry['link'] else: text += entry['error'] text += "\n==================\n" maildata = { "fromAddr": "Indico Mailer <%s>" % Config.getInstance().getNoReplyEmail(), "toList": [user.getEmail()], "subject": _("[%s] Login Information") % getSubjectIndicoTitle(), "body": text } GenericMailer.send(GenericNotification(maildata))
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'
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'
class IndicoSessionInterface(SessionInterface): pickle_based = True serializer = cPickle session_class = IndicoSession temporary_session_lifetime = timedelta(days=7) def __init__(self): self.storage = GenericCache('flask-session') def generate_sid(self): return str(uuid.uuid4()) def get_cookie_secure(self, app): return request.is_secure def get_storage_lifetime(self, app, session): # Permanent sessions are stored for exactly the same duration as the session id cookie. # "Temporary" session are stored for a period that is not too short/long as some people # close their browser very rarely and thus shouldn't be logged out that often. if session.permanent: return app.permanent_session_lifetime else: return self.temporary_session_lifetime def should_refresh_session(self, app, session): if session.new or '_expires' not in session: return False threshold = self.get_storage_lifetime(app, session) / 2 return session['_expires'] - datetime.now() < threshold def should_refresh_sid(self, app, session): return self.get_cookie_secure(app) and not session.get('_secure') def open_session(self, app, request): sid = request.cookies.get(app.session_cookie_name) if not sid: return self.session_class(sid=self.generate_sid(), new=True) data = self.storage.get(sid) if data is not None: return self.session_class(self.serializer.loads(data), sid=sid) return self.session_class(sid=self.generate_sid(), new=True) def save_session(self, app, session, response): domain = self.get_cookie_domain(app) secure = self.get_cookie_secure(app) refresh_sid = self.should_refresh_sid(app, session) if not session and not session.new: # empty session, delete it from storage and cookie self.storage.delete(session.sid) response.delete_cookie(app.session_cookie_name, domain=domain) return if not refresh_sid and not session.modified and not self.should_refresh_session(app, session): # If the session has not been modified we only store if it needs to be refreshed return if app.config['INDICO_SESSION_PERMANENT']: # Setting session.permanent marks the session as modified so we only set it when we # are saving the session anyway! session.permanent = True storage_ttl = self.get_storage_lifetime(app, session) cookie_lifetime = self.get_expiration_time(app, session) session['_expires'] = datetime.now() + storage_ttl if refresh_sid: self.storage.delete(session.sid) session.sid = self.generate_sid() session['_secure'] = request.is_secure self.storage.set(session.sid, self.serializer.dumps(dict(session)), storage_ttl) response.set_cookie(app.session_cookie_name, session.sid, expires=cookie_lifetime, httponly=True, secure=secure)
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'
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'
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"
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() 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' oauthToken = 'oauth_token' in queryParams # 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.user: # 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.user) userPrefix = 'user-' + used_session.user.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: # 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 = HelperMaKaCInfo.getMaKaCInfoInstance().getAPICacheTTL() 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'
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' 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() 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, 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'
class IndicoSessionInterface(SessionInterface): pickle_based = True serializer = cPickle session_class = IndicoSession temporary_session_lifetime = timedelta(days=7) def __init__(self): self.storage = GenericCache('flask-session') def generate_sid(self): return str(uuid.uuid4()) def get_cookie_secure(self, app): return request.is_secure def get_storage_lifetime(self, app, session): # Permanent sessions are stored for exactly the same duration as the session id cookie. # "Temporary" session are stored for a period that is not too short/long as some people # close their browser very rarely and thus shouldn't be logged out that often. if session.permanent: return app.permanent_session_lifetime else: return self.temporary_session_lifetime def should_refresh_session(self, app, session): if session.new or '_expires' not in session: return False threshold = self.get_storage_lifetime(app, session) / 2 return session['_expires'] - datetime.now() < threshold def should_refresh_sid(self, app, session): if not session.new and self.get_cookie_secure( app) and not session.get('_secure'): return True if getattr(session, '_refresh_sid', False): return True return False def open_session(self, app, request): sid = request.cookies.get(app.session_cookie_name) if not sid: return self.session_class(sid=self.generate_sid(), new=True) data = self.storage.get(sid) if data is not None: return self.session_class(self.serializer.loads(data), sid=sid) return self.session_class(sid=self.generate_sid(), new=True) def save_session(self, app, session, response): domain = self.get_cookie_domain(app) secure = self.get_cookie_secure(app) refresh_sid = self.should_refresh_sid(app, session) if not session and not session.new: # empty session, delete it from storage and cookie self.storage.delete(session.sid) response.delete_cookie(app.session_cookie_name, domain=domain) return if not refresh_sid and not session.modified and not self.should_refresh_session( app, session): # If the session has not been modified we only store if it needs to be refreshed return if app.config['INDICO_SESSION_PERMANENT']: # Setting session.permanent marks the session as modified so we only set it when we # are saving the session anyway! session.permanent = True storage_ttl = self.get_storage_lifetime(app, session) cookie_lifetime = self.get_expiration_time(app, session) session['_expires'] = datetime.now() + storage_ttl if refresh_sid: self.storage.delete(session.sid) session.sid = self.generate_sid() session['_secure'] = request.is_secure self.storage.set(session.sid, self.serializer.dumps(dict(session)), storage_ttl) response.set_cookie(app.session_cookie_name, session.sid, expires=cookie_lifetime, httponly=True, secure=secure)
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'