def __init__(self, **kwargs): self.task_data = {'cmd': None} self.request = kwargs.pop('request', {}) self.response = kwargs.pop('response', {}) try: self.session = self.request.env['session'] self.input = self.request.context['data'] self.output = self.request.context['result'] self.user_id = self.session.get('user_id') self.role_id = self.session.get('role_id') except AttributeError: # when we want to use engine functions independently, # we need to create a fake current object self.session = {} self.input = {} self.output = {} self.user_id = None self.role_id = None self.lang_code = self.input.get('lang_code', settings.DEFAULT_LANG) self.log = log self.pool = {} AuthBackend = get_object_from_path(settings.AUTH_BACKEND) self.auth = lazy_object_proxy.Proxy(lambda: AuthBackend(self)) self.user = lazy_object_proxy.Proxy(lambda: self.auth.get_user()) self.role = lazy_object_proxy.Proxy(lambda: self.auth.get_role()) self.msg_cache = Notify(self.user_id) log.debug("\n\nINPUT DATA: %s" % self.input) self.permissions = []
def __init__(self, **kwargs): super(WFCurrent, self).__init__(**kwargs) self.workflow_name = kwargs.pop('workflow_name', '') self.spec = None self.workflow = None self.task_type = '' self.task = None self.pool = {} self.task_name = '' self.activity = '' self.lane_permissions = [] self.lane_relations = '' self.old_lane = '' self.lane_owners = None self.lane_name = '' if 'token' in self.input: self.token = self.input['token'] log.info("TOKEN iNCOMiNG: %s " % self.token) self.new_token = False else: self.token = uuid4().hex self.new_token = True log.info("TOKEN NEW: %s " % self.token) self.wfcache = WFCache(self.token) log.debug("\n\nWF_CACHE: %s" % self.wfcache.get()) self.set_client_cmds()
def __init__(self, **kwargs): self.task_data = {'cmd': None} self.session = Session() self.headers = {} self.input = {} # when we want to use engine functions independently, self.output = {} # we need to create a fake current object try: self.session = kwargs['session'] self.input = kwargs['input'] except KeyError: self.request = kwargs.pop('request', {}) self.response = kwargs.pop('response', {}) if 'env' in self.request: self.session = self.request.env['session'] self.input = self.request.context['data'] self.output = self.request.context['result'] self.remote_addr = None self.user_id = self.session.get('user_id') self.role_id = self.session.get('role_id') self.log = log self.pool = {} AuthBackend = get_object_from_path(settings.AUTH_BACKEND) self.auth = lazy_object_proxy.Proxy(lambda: AuthBackend(self)) self.user = lazy_object_proxy.Proxy(lambda: self.auth.get_user()) self.role = lazy_object_proxy.Proxy(lambda: self.auth.get_role()) log.debug("\n\nINPUT DATA: %s" % self.input) self.permissions = []
def check_for_permission(self): # TODO: Works but not beautiful, needs review! """ Checks if current user (or role) has the required permission for current workflow step. Raises: HTTPError: if user doesn't have required permissions. """ if self.current.task: lane = self.current.lane_id permission = "%s.%s.%s" % (self.current.workflow_name, lane, self.current.task_name) else: permission = self.current.workflow_name log.debug("CHECK PERM: %s" % permission) if (self.current.task_type not in PERM_REQ_TASK_TYPES or permission.startswith(tuple(settings.ANONYMOUS_WORKFLOWS)) or (self.current.is_auth and permission.startswith(tuple(settings.COMMON_WORKFLOWS)))): return # FIXME:needs hardening log.debug("REQUIRE PERM: %s" % permission) if not self.current.has_permission(permission): raise HTTPError( 403, "You don't have required permission: %s" % permission)
def _load_translations(): all_translations = {} log.debug('Loading translations') for language in settings.TRANSLATIONS: translations = {} for domain, default_lang in settings.TRANSLATION_DOMAINS.items(): if language == default_lang: # For the default language of the domain, use untranslated messages catalog = gettextlib.NullTranslations() else: # For other languages, we need to insert the translations log.debug( 'Loading translation of language {lang} for {domain}'.format( lang=language, domain=domain)) try: catalog = gettextlib.translation( domain=domain, localedir=settings.TRANSLATIONS_DIR, languages=[language], fallback=False, ) except IOError: log.error('Translations for language {lang} for {domain} not found! ' 'Falling back to default language!'.format(lang=language, domain=domain)) catalog = gettextlib.NullTranslations() translations[domain] = catalog all_translations[language] = translations return all_translations
def start_engine(self, **kwargs): self.current = WFCurrent(**kwargs) self.check_for_authentication() self.check_for_permission() self.workflow = self.load_or_create_workflow() log.debug( "\n\n::::::::::: ENGINE STARTED :::::::::::\n" "\tWF: %s (Possible) TASK:%s\n" "\tCMD:%s\n" "\tSUBCMD:%s" % (self.workflow.name, self.workflow.get_tasks(Task.READY), self.current.input.get('cmd'), self.current.input.get('subcmd'))) self.current.workflow = self.workflow
def start_engine(self, **kwargs): self.current = WFCurrent(**kwargs) self.check_for_authentication() self.check_for_permission() self.workflow = self.load_or_create_workflow() log.debug("\n\n::::::::::: ENGINE STARTED :::::::::::\n" "\tWF: %s (Possible) TASK:%s\n" "\tCMD:%s\n" "\tSUBCMD:%s" % ( self.workflow.name, self.workflow.get_tasks(Task.READY), self.current.input.get('cmd'), self.current.input.get('subcmd'))) self.current.workflow = self.workflow
def check_for_permission(self): """ since wf task has their own perm. checker, this method called only by "call()" dispatcher """ permission = "%s.%s" % (self.object.__class__.__name__, self.cmd) log.debug("CHECK CRUD PERM: %s" % permission) if (self.current.task_type in NO_PERM_TASKS_TYPES or permission in settings.ANONYMOUS_WORKFLOWS): return if not self.current.has_permission(permission): raise falcon.HTTPForbidden("Permission denied", "You don't have required CRUD permission: %s" % permission)
def check_for_permission(self): # TODO: Works but not beautiful, needs review! if self.current.task: permission = "%s.%s" % (self.current.workflow_name, self.current.task_name) else: permission = self.current.workflow_name log.debug("CHECK PERM: %s" % permission) if (self.current.task_type in NO_PERM_TASKS_TYPES or permission.startswith(tuple(settings.ANONYMOUS_WORKFLOWS))): return log.debug("REQUIRE PERM: %s" % permission) if not self.current.has_permission(permission): raise falcon.HTTPForbidden("Permission denied", "You don't have required permission: %s" % permission)
def process_response(self, req, resp, resource): if 'result' not in req.context: return req.context['result']['is_login'] = '******' in req.env['session'] if settings.DEBUG: req.context['result']['_debug_queries'] = sys._debug_db_queries sys._debug_db_queries = [] if resp.body is None and req.context['result']: resp.body = json.dumps(req.context['result']) try: log.debug("RESPONSE: %s" % resp.body) except: log.exception("ERR: RESPONSE CANT BE LOGGED ")
def check_for_permission(self): """ since wf task has their own perm. checker, this method called only by "call()" dispatcher """ permission = "%s.%s" % (self.object.__class__.__name__, self.cmd) log.debug("CHECK CRUD PERM: %s" % permission) if (self.current.task_type in NO_PERM_TASKS_TYPES or permission in settings.ANONYMOUS_WORKFLOWS): return if not self.current.has_permission(permission): raise falcon.HTTPForbidden( "Permission denied", "You don't have required CRUD permission: %s" % permission)
def start_engine(self, **kwargs): """ Initializes the workflow with given request, response objects and diagram name. Args: session: input: workflow_name (str): Name of workflow diagram without ".bpmn" suffix. File must be placed under one of configured :py:attr:`~zengine.settings.WORKFLOW_PACKAGES_PATHS` """ self.current = WFCurrent(**kwargs) self.wf_state = {'in_external': False, 'finished': False} if not self.current.new_token: self.wf_state = self.current.wf_cache.get(self.wf_state) self.current.workflow_name = self.wf_state['name'] # if we have a pre-selected object to work with, # inserting it as current.input['id'] and task_data['object_id'] if 'subject' in self.wf_state: self.current.input['id'] = self.wf_state['subject'] self.current.task_data['object_id'] = self.wf_state['subject'] self.check_for_authentication() self.check_for_permission() self.workflow = self.load_or_create_workflow() # if form data exists in input (user submitted) # put form data in wf task_data if 'form' in self.current.input: form = self.current.input['form'] if 'form_name' in form: self.current.task_data[form['form_name']] = form # in wf diagram, if property is stated as init = True # demanded initial values are assigned and put to cache start_init_values = self.workflow_spec.wf_properties.get( 'init', 'False') == 'True' if start_init_values: WFInit = get_object_from_path(settings.WF_INITIAL_VALUES)() WFInit.assign_wf_initial_values(self.current) log_msg = ( "\n\n::::::::::: ENGINE STARTED :::::::::::\n" "\tWF: %s (Possible) TASK:%s\n" "\tCMD:%s\n" "\tSUBCMD:%s" % (self.workflow.name, self.workflow.get_tasks(Task.READY), self.current.input.get('cmd'), self.current.input.get('subcmd'))) log.debug(log_msg) sys._zops_wf_state_log = log_msg self.current.workflow = self.workflow
def send_to_prv_exchange(self, user_id, message=None): """ Send messages through logged in users private exchange. Args: user_id string: User key message dict: Message object """ exchange = 'prv_%s' % user_id.lower() msg = json.dumps(message, cls=ZEngineJSONEncoder) log.debug("Sending following users \"%s\" exchange:\n%s " % (exchange, msg)) self.get_channel().publish(exchange=exchange, routing_key='', body=msg)
def send_to_default_exchange(self, sess_id, message=None): """ Send messages through RabbitMQ's default exchange, which will be delivered through routing_key (sess_id). This method only used for un-authenticated users, i.e. login process. Args: sess_id string: Session id message dict: Message object. """ msg = json.dumps(message, cls=ZEngineJSONEncoder) log.debug( "Sending following message to %s queue through default exchange:\n%s" % (sess_id, msg)) self.get_channel().publish(exchange='', routing_key=sess_id, body=msg)
def check_for_permission(self): # TODO: Works but not beautiful, needs review! if self.current.task: permission = "%s.%s" % (self.current.workflow_name, self.current.task_name) else: permission = self.current.workflow_name log.debug("CHECK PERM: %s" % permission) if (self.current.task_type in NO_PERM_TASKS_TYPES or permission.startswith(tuple(settings.ANONYMOUS_WORKFLOWS))): return log.debug("REQUIRE PERM: %s" % permission) if not self.current.has_permission(permission): raise falcon.HTTPForbidden( "Permission denied", "You don't have required permission: %s" % permission)
def check_for_permission(self): """ Checks permissions of auto-generated CRUD views. Required permissions calculated according to ``ModelName . self.cmd`` scheme. """ permission = "%s.%s" % (self.object.__class__.__name__, self.cmd) log.debug("CHECK CRUD PERM: %s" % permission) if (self.current.task_type not in PERM_REQ_TASK_TYPES or permission in settings.ANONYMOUS_WORKFLOWS): return if not self.current.has_permission(permission): raise HTTPError( 403, "You don't have required CRUD permission: %s" % permission)
def process_response(self, request, response, resource): origin = request.get_header('Origin') if not settings.DEBUG: if origin in settings.ALLOWED_ORIGINS or not origin: response.set_header('Access-Control-Allow-Origin', origin) else: log.debug("CORS ERROR: %s not allowed, allowed hosts: %s" % (origin, settings.ALLOWED_ORIGINS)) raise falcon.HTTPForbidden("Denied", "Origin not in ALLOWED_ORIGINS: %s" % origin) response.status = falcon.HTTP_403 else: response.set_header('Access-Control-Allow-Origin', origin or '*') response.set_header('Access-Control-Allow-Credentials', "true") response.set_header('Access-Control-Allow-Headers', 'Content-Type') # This could be overridden in the resource level response.set_header('Access-Control-Allow-Methods', 'OPTIONS')
def _do_login(self): """ logs in the "test_user" """ self.client.sess_id = uuid4().hex self.client.set_path("/login/") resp = self.client.post() assert resp.json['forms']['schema']['title'] == 'LoginForm' req_fields = resp.json['forms']['schema']['required'] assert all([(field in req_fields) for field in ('username', 'password')]) resp = self.client.post(username=self.client.username or self.client.user.username, password="******", cmd="do") log.debug("login result :\n%s" % resp.json) assert resp.json['cmd'] == 'upgrade'
def switch_to_external_wf(self): """ External workflow switcher. This method copies main workflow information into a temporary dict `main_wf` and makes external workflow acting as main workflow. """ # External WF name should be stated at main wf diagram and type should be service task. if (self.current.task_type == 'ServiceTask' and self.current.task.task_spec.type == 'external'): log.debug("Entering to EXTERNAL WF") # Main wf information is copied to main_wf. main_wf = self.wf_state.copy() # workflow name from main wf diagram is assigned to current workflow name. # workflow name must be either in task_data with key 'external_wf' or in main diagram's # topic. self.current.workflow_name = self.current.task_data.pop('external_wf', False) or self.\ current.task.task_spec.topic # For external WF, check permission and authentication. But after cleaning current task. self._clear_current_task() # check for auth and perm. current task cleared, do against new workflow_name self.check_for_authentication() self.check_for_permission() # wf knowledge is taken for external wf. self.workflow_spec = self.get_worfklow_spec() # New WF instance is created for external wf. self.workflow = self.create_workflow() # Current WF is this WF instance. self.current.workflow = self.workflow # main_wf: main wf information. # in_external: it states external wf in progress. # finished: it shows that main wf didn't finish still progress in external wf. self.wf_state = { 'main_wf': main_wf, 'in_external': True, 'finished': False }
def log_wf_state(self): """ logging the state of the workflow and data """ output = '\n- - - - - -\n' output += "WORKFLOW: %s ( %s )" % (self.current.workflow_name.upper(), self.current.workflow.name) output += "\nTASK: %s ( %s )\n" % (self.current.task_name, self.current.task_type) output += "DATA:" for k, v in self.current.task_data.items(): if v: output += "\n\t%s: %s" % (k, v) output += "\nCURRENT:" output += "\n\tACTIVITY: %s" % self.current.activity output += "\n\tPOOL: %s" % self.current.pool output += "\n\tTOKEN: %s" % self.current.token log.debug(output + "\n= = = = = =\n")
def process_response(self, request, response, resource): origin = request.get_header('Origin') if not settings.DEBUG: if origin in settings.ALLOWED_ORIGINS or not origin: response.set_header('Access-Control-Allow-Origin', origin) else: log.debug("CORS ERROR: %s not allowed, allowed hosts: %s" % (origin, settings.ALLOWED_ORIGINS)) raise falcon.HTTPForbidden( "Denied", "Origin not in ALLOWED_ORIGINS: %s" % origin) response.status = falcon.HTTP_403 else: response.set_header('Access-Control-Allow-Origin', origin or '*') response.set_header('Access-Control-Allow-Credentials', "true") response.set_header('Access-Control-Allow-Headers', 'Content-Type') # This could be overridden in the resource level response.set_header('Access-Control-Allow-Methods', 'OPTIONS')
def install_language(cls, language_code): """Install the translations for language specified by `language_code`. If we don't have translations for this language, then the default language will be used. If the language specified is already installed, then this is a no-op. """ # Skip if the language is already installed if language_code == cls.language: return try: cls._active_catalogs = cls._translation_catalogs[language_code] cls.language = language_code log.debug('Installed language %s', language_code) except KeyError: default = settings.DEFAULT_LANG log.warning('Unknown language %s, falling back to %s', language_code, default) cls._active_catalogs = cls._translation_catalogs[default] cls.language = default
def install_locale(cls, locale_code, locale_type): """Install the locale specified by `language_code`, for localizations of type `locale_type`. If we can't perform localized formatting for the specified locale, then the default localization format will be used. If the locale specified is already installed for the selected type, then this is a no-op. """ # Skip if the locale is already installed if locale_code == getattr(cls, locale_type): return try: # We create a Locale instance to see if the locale code is supported locale = Locale(locale_code) log.debug('Installed locale %s', locale_code) except UnknownLocaleError: default = settings.DEFAULT_LOCALIZATION_FORMAT log.warning('Unknown locale %s, falling back to %s', locale_code, default) locale = Locale(default) setattr(cls, locale_type, locale.language)
def process_response(self, req, resp, resource): """ Serializes ``req.context['result']`` to resp.body as JSON. If :attr:`~zengine.settings.DEBUG` is True, ``sys._debug_db_queries`` (set by pyoko) added to response. """ if 'result' not in req.context: return req.context['result']['is_login'] = '******' in req.env['session'] if settings.DEBUG: req.context['result']['_debug_queries'] = sys._debug_db_queries sys._debug_db_queries = [] if resp.body is None and req.context['result']: resp.body = json.dumps(req.context['result']) try: log.debug("RESPONSE: %s" % resp.body) except: log.exception("ERR: RESPONSE CANT BE LOGGED ")
def check_for_lane_permission(self): """ One or more permissions can be associated with a lane of a workflow. In a similar way, a lane can be restricted with relation to other lanes of the workflow. When this method called on lane changes, it checks if the current user has the required permissions and proper relations. Raises a HTTPForbidden error if it is not. """ # TODO: Cache lane_data in app memory if self.current.lane_permissions: log.debug("HAS LANE PERMS: %s" % self.current.lane_permissions) for perm in self.current.lane_permissions: if not self.current.has_permission(perm): raise falcon.HTTPForbidden( "Permission denied", "You don't have required lane permission: %s" % perm) if self.current.lane_relations: context = self.get_pool_context() log.debug("HAS LANE RELS: %s" % self.current.lane_relations) if not eval(self.current.lane_relations, context): log.debug("LANE RELATION ERR: %s %s" % (self.current.lane_relations, context)) raise falcon.HTTPForbidden( "Permission denied", "You aren't qualified for this lane: %s" % self.current.lane_relations)
def get_model_class(self): """ Looks for the default model of this view from :py:attr:`Meta.model`. If it's not set, tries to get model name from ``current.input['model']``. Can be overridden to implement different model selection mechanism. Returns: :py:attr:`~pyoko.models.Model` class. """ try: model = self.Meta.model if self.Meta.model else self.current.input[ 'model'] if isinstance(model, Model): return model else: return model_registry.get_model(model) except: log.debug('No "model" given for CrudView') return None
def check_for_lane_permission(self): """ One or more permissions can be associated with a lane of a workflow. In a similar way, a lane can be restricted with relation to other lanes of the workflow. This method called on lane changes and checks user has required permissions and relations. Raises: HTTPForbidden: if the current user hasn't got the required permissions and proper relations """ # TODO: Cache lane_data in app memory if self.current.lane_permission: log.debug("HAS LANE PERM: %s" % self.current.lane_permission) perm = self.current.lane_permission if not self.current.has_permission(perm): raise HTTPError( 403, "You don't have required lane permission: %s" % perm) if self.current.lane_relations: context = self.get_pool_context() log.debug("HAS LANE RELS: %s" % self.current.lane_relations) try: cond_result = eval(self.current.lane_relations, context) except: log.exception("CONDITION EVAL ERROR : %s || %s" % (self.current.lane_relations, context)) raise if not cond_result: log.debug("LANE RELATION ERR: %s %s" % (self.current.lane_relations, context)) raise HTTPError( 403, "You aren't qualified for this lane: %s" % self.current.lane_relations)
def check_for_lane_permission(self): """ One or more permissions can be associated with a lane of a workflow. In a similar way, a lane can be restricted with relation to other lanes of the workflow. When this method called on lane changes, it checks if the current user has the required permissions and proper relations. Raises a HTTPForbidden error if it is not. """ # TODO: Cache lane_data in app memory if self.current.lane_permissions: log.debug("HAS LANE PERMS: %s" % self.current.lane_permissions) for perm in self.current.lane_permissions: if not self.current.has_permission(perm): raise falcon.HTTPForbidden("Permission denied", "You don't have required lane permission: %s" % perm) if self.current.lane_relations: context = self.get_pool_context() log.debug("HAS LANE RELS: %s" % self.current.lane_relations) if not eval(self.current.lane_relations, context): log.debug("LANE RELATION ERR: %s %s" % (self.current.lane_relations, context)) raise falcon.HTTPForbidden( "Permission denied", "You aren't qualified for this lane: %s" % self.current.lane_relations)
def log_wf_state(self): log.debug(self.generate_wf_state_log() + "\n= = = = = =\n")