Пример #1
0
 def handle_message(self, message):
     """
     Given a message dictionary, perform the relevant RPC actions and send
     out the response.  This function is called from a pool of background
     threads
     """
     before = time.time()
     duration, result = None, None
     threadlocal.reset(websocket=self, message=message, headers=self.header_fields, **self.session_fields)
     action, callback, client, method = message.get('action'), message.get('callback'), message.get('client'), message.get('method')
     try:
         with self.client_lock(client):
             self.internal_action(action, client, callback)
             if method:
                 self.clear_cached_response(client, callback)
                 func = self.get_method(method)
                 args, kwargs = get_params(message.get('params'))
                 result = self.NO_RESPONSE
                 try:
                     result = func(*args, **kwargs)
                     duration = (time.time() - before) if config['debug'] else None
                 finally:
                     trigger_delayed_notifications()
                     self.update_triggers(client, callback, func, args, kwargs, result, duration)
     except:
         log.error('unexpected websocket dispatch error', exc_info=True)
         exc_class, exc, tb = sys.exc_info()
         str_content = str(exc) or 'Unexpected Error.'
         message = (str_content + '\n' + traceback.format_exc()) if config['debug'] else str_content
         self.send(error=message, callback=callback, client=client)
     else:
         if callback is not None and result is not self.NO_RESPONSE:
             self.send(data=result, callback=callback, client=client, _time=duration)
Пример #2
0
 def handle_message(self, message):
     before = time.time()
     duration, result = None, None
     threadlocal.reset(websocket=self, message=message, username=self.username)
     action, callback, client, method = message.get('action'), message.get('callback'), message.get('client'), message.get('method')
     try:
         with self.client_lock(client):
             self.internal_action(action, client, callback)
             if method:
                 func = self.get_method(method)
                 args, kwargs = get_params(message.get('params'))
                 result = self.NO_RESPONSE
                 try:
                     result = func(*args, **kwargs)
                     duration = (time.time() - before) if config['debug'] else None
                 finally:
                     self.update_triggers(client, callback, func, args, kwargs, result, duration)
     except:
         log.error('unexpected websocket dispatch error', exc_info=True)
         exc_class, exc, tb = sys.exc_info()
         str_content = str(exc) or 'Unexpected Error.'
         message = (str_content + '\n' + traceback.format_exc()) if config['debug'] else str_content
         self.send(error=message, callback=callback, client=client)
     else:
         if callback is not None and result is not self.NO_RESPONSE:
             self.send(data=result, callback=callback, client=client, _time=duration)
Пример #3
0
    def run(self):
        while not self.stopped.is_set():
            try:
                self.func()
            except:
                log.error('unexpected error', exc_info=True)

            if self.interval:
                self.stopped.wait(self.interval)
Пример #4
0
 def received_message(self, message):
     s = str(message)
     log.debug('received {!r}', s)
     try:
         parsed = json.loads(s)
     except:
         log.error('failed to parse incoming message', exc_info=True)
     else:
         self.dispatcher.defer(parsed)
Пример #5
0
    def run(self):
        while not self.stopped.is_set():
            try:
                self.func()
            except:
                log.error('unexpected error', exc_info=True)

            if self.interval:
                self.stopped.wait(self.interval)
Пример #6
0
    def run(self):
        while not self.stopped.is_set():
            try:
                self.func()
            except:
                log.error('unexpected error', exc_info=True)

            interval = config['thread_wait_interval'] if self.interval is None else self.interval
            if interval:
                self.stopped.wait(interval)
Пример #7
0
 def upgrade(self, **kwargs):
     try:
         kwargs['handler_cls'].check_authentication()
     except WebSocketAuthError:
         raise cherrypy.HTTPError(401, 'You must be logged in to establish a websocket connection.')
     except:
         log.error('unexpected websocket authentication error', exc_info=True)
         raise cherrypy.HTTPError(401, 'unexpected authentication error')
     else:
         return WebSocketTool.upgrade(self, **kwargs)
Пример #8
0
 def _poll(self):
     with self._lock:
         assert self.ws and self.ws.connected, 'cannot poll while websocket is not connected'
         try:
             self.call(self.poll_method)
         except:
             log.error('no poll response received from {!r}, closing connection, will attempt to reconnect', self.url, exc_info=True)
             self.ws.close()
         else:
             self._last_poll = datetime.now()
Пример #9
0
 def _send(self, **kwargs):
     log.debug('sending {}', kwargs)
     with self._lock:
         assert self.connected, 'tried to send data on closed websocket {!r}'.format(self.url)
         try:
             return self.ws.send(kwargs)
         except:
             log.error('failed to send {!r} on {!r}, closing websocket and will attempt to reconnect', kwargs, self.url)
             self.ws.close()
             raise
Пример #10
0
 def received_message(self, message):
     try:
         fields = json.loads(str(message.data))
         assert isinstance(fields, dict)
     except:
         message = 'incoming websocket message was not a json object: {}'.format(message.data)
         log.error(message)
         self.send(error=message)
     else:
         log.debug('received {}', fields)
         responder.defer(self, fields)
Пример #11
0
def _check_sometimes_required_options():
    missing = []
    for optname in ['subscription_host', 'ldap.url', 'ldap.basedn']:
        val = config[optname]
        if not val or isinstance(val, (list, tuple)) and not filter(bool, val):
            missing.append(optname)

    if missing:
        message = 'missing configuration options: {}'.format(missing)
        log.error(message)
        raise ConfigurationError(message)
Пример #12
0
    def check_authentication(cls):
        host, origin = cherrypy.request.headers['host'], cherrypy.request.headers['origin']
        if ('//' + host) not in origin:
            log.error('Javascript websocket connections must follow same-origin policy; origin {!r} does not match host {!r}', origin, host)
            raise ValueError('Origin and Host headers do not match')

        if config['ws.auth_required'] and 'username' not in cherrypy.session:
            log.warning('websocket connections to this address must have a valid session')
            raise ValueError('you are not logged in')

        return cherrypy.session.get('username', '<UNAUTHENTICATED>')
Пример #13
0
 def received_message(self, message):
     try:
         data = message.data if isinstance(message.data, six.text_type) else message.data.decode('utf-8')
         fields = json.loads(data)
         assert isinstance(fields, dict)
     except:
         message = 'incoming websocket message was not a json object: {}'.format(message.data)
         log.error(message)
         self.send(error=message)
     else:
         log.debug('received {}', fields)
         responder.defer(self, fields)
Пример #14
0
 def fallback(self, message):
     """
     Handler method which is called for incoming websocket messages which
     aren't valid responses to an outstanding call or subscription.  By
     default this just logs an error message.  You can override this by
     subclassing this class, or just by assigning a hander method, e.g.
     
     >>> ws = WebSocket()
     >>> ws.fallback = some_handler_function
     >>> ws.connect()
     """
     _, exc, _ = sys.exc_info()
     log.error('no callback registered for message {!r}, message ignored: {}', message, exc)
Пример #15
0
def local_broadcast(channels, trigger=None, originating_client=None):
    """Triggers callbacks registered via @locally_subscribes"""
    triggered = set()
    for channel in sideboard.lib.listify(channels):
        for callback in local_subscriptions[channel]:
            triggered.add(callback)

    for callback in triggered:
        threadlocal.reset(trigger=trigger, originating_client=originating_client)
        try:
            callback()
        except:
            log.error('unexpected error on local broadcast callback', exc_info=True)
Пример #16
0
 def upgrade(self, **kwargs):
     try:
         kwargs['handler_cls'].check_authentication()
     except WebSocketAuthError:
         raise cherrypy.HTTPError(
             401,
             'You must be logged in to establish a websocket connection.')
     except:
         log.error('unexpected websocket authentication error',
                   exc_info=True)
         raise cherrypy.HTTPError(401, 'unexpected authentication error')
     else:
         return WebSocketTool.upgrade(self, **kwargs)
Пример #17
0
 def fallback(self, message):
     """
     Handler method which is called for incoming websocket messages which
     aren't valid responses to an outstanding call or subscription.  By
     default this just logs an error message.  You can override this by
     subclassing this class, or just by assigning a hander method, e.g.
     
     >>> ws = WebSocket()
     >>> ws.fallback = some_handler_function
     >>> ws.connect()
     """
     _, exc, _ = sys.exc_info()
     log.error('no callback registered for message {!r}, message ignored: {}', message, exc)
Пример #18
0
def mainloop_daemon():
    log.info('starting Sideboard daemon process')
    args = parser.parse_args()
    if os.fork() == 0:
        pid = os.fork()
        if pid == 0:
            mainloop()
        else:
            log.debug('writing pid ({}) to pidfile ({})', pid, args.pidfile)
            try:
                with open(args.pidfile, 'w') as f:
                    f.write('{}'.format(pid))
            except:
                log.error('unexpected error writing pid ({}) to pidfile ({})', pid, args.pidfile, exc_info=True)
Пример #19
0
 def received_message(self, message):
     try:
         data = message.data if isinstance(
             message.data, six.text_type) else message.data.decode('utf-8')
         fields = json.loads(data)
         assert isinstance(fields, dict)
     except:
         message = 'incoming websocket message was not a json object: {}'.format(
             message.data)
         log.error(message)
         self.send(error=message)
     else:
         log.debug('received {}', fields)
         responder.defer(self, fields)
Пример #20
0
def local_broadcast(channels, trigger=None, originating_client=None):
    """Triggers callbacks registered via @locally_subscribes"""
    triggered = set()
    for channel in sideboard.lib.listify(channels):
        for callback in local_subscriptions[channel]:
            triggered.add(callback)

    for callback in triggered:
        threadlocal.reset(trigger=trigger,
                          originating_client=originating_client)
        try:
            callback()
        except:
            log.error('unexpected error on local broadcast callback',
                      exc_info=True)
Пример #21
0
def ldap_auth(username, password):
    if not username or not password:
        return False

    try:
        ssl_material = (
            config['ldap.cacert'], config['ldap.cert'], config['ldap.key']
        )
        server_kwargs = {}
        tls_kwargs = {}

        if config['ldap.url'].startswith('ldaps') or any(ssl_material):
            server_kwargs['use_ssl'] = True
        else:
            server_kwargs['use_ssl'] = False
        server_kwargs['host'] = config['ldap.url']

        if config['ldap.cacert']:
            tls_kwargs['ca_certs_file'] = config['ldap.cacert']
            # if we specify a CA certs file, assume we want to validate it
            tls_kwargs['validate'] = ssl.CERT_REQUIRED

        if tls_kwargs:
            server_kwargs['tls'] = ldap3.Tls(**tls_kwargs)

        server = ldap3.Server(**server_kwargs)

    except:
        log.error('Error initializing LDAP server', exc_info=True)
        raise

    # attempt to bind on each base DN that was configured
    for basedn in listify(config['ldap.basedn']):
        dn = '{}={},{}'.format(config['ldap.userattr'], username, basedn)
        log.debug('attempting to bind with dn {}', dn)
        try:
            connection = ldap3.Connection(server, user=dn, password=password)
            connection.start_tls()
            is_bound = connection.bind()
        except:
            log.warning("Error binding to LDAP server with dn", exc_info=True)
            raise

        if is_bound:
            return True

    # we couldn't auth on anything
    return False
Пример #22
0
    def check_authentication(cls):
        host, origin = cherrypy.request.headers[
            'host'], cherrypy.request.headers['origin']
        if ('//' + host) not in origin:
            log.error(
                'Javascript websocket connections must follow same-origin policy; origin {!r} does not match host {!r}',
                origin, host)
            raise ValueError('Origin and Host headers do not match')

        if config['ws.auth_required'] and 'username' not in cherrypy.session:
            log.warning(
                'websocket connections to this address must have a valid session'
            )
            raise ValueError('you are not logged in')

        return cherrypy.session.get('username', '<UNAUTHENTICATED>')
Пример #23
0
def _make_jsonrpc_handler(services, debug=config['debug'],
                         precall=lambda body: None,
                         errback=lambda err, message: log.error(message, exc_info=True)):
    @cherrypy.expose
    @cherrypy.tools.force_json_in()
    @cherrypy.tools.json_out(handler=json_handler)
    def jsonrpc_handler(self):
        id = None

        def error(code, message):
            body = {'jsonrpc': '2.0', 'id': id,
                    'error': {'code': code, 'message': message}}
            log.warn('returning error message: {!r}', body)
            return body

        body = cherrypy.request.json
        if not isinstance(body, dict):
            return error(ERR_INVALID_JSON, 'invalid json input {!r}'.format(
                cherrypy.request.body))

        log.debug('jsonrpc request body: {!r}', body)

        id, params = body.get('id'), body.get('params', [])
        if 'method' not in body:
            return error(ERR_INVALID_RPC,
                         '"method" field required for jsonrpc request')

        method = body['method']
        if method.count('.') != 1:
            return error(ERR_MISSING_FUNC, 'invalid method ' + method)

        module, function = method.split('.')
        if module not in services:
            return error(ERR_MISSING_FUNC, 'no module ' + module)

        service = services[module]
        if not hasattr(service, function):
            return error(ERR_MISSING_FUNC, 'no function ' + method)

        if not isinstance(params, (list, dict)):
            return error(ERR_INVALID_PARAMS,
                         'invalid parameter list: {!r}'.format(params))

        args, kwargs = (params, {}) if isinstance(params, list) else ([], params)

        precall(body)
        try:
            response = {'jsonrpc': '2.0', 'id': id,
                        'result': getattr(service, function)(*args, **kwargs)}
            log.debug('returning success message: {!r}', response)
            return response
        except Exception as e:
            errback(e, 'unexpected jsonrpc error calling ' + method)
            message = 'unexpected error'
            if debug:
                message += ': ' + traceback.format_exc()
            return error(ERR_FUNC_EXCEPTION, message)

    return jsonrpc_handler
Пример #24
0
 def received_message(self, message):
     """
     This overrides the default ws4py event handler to parse the incoming
     message and pass it off to our pool of background threads, which call
     this class' handle_message function to perform the relevant RPC actions.
     """
     try:
         data = message.data if isinstance(message.data, six.text_type) else message.data.decode('utf-8')
         fields = json.loads(data)
         assert isinstance(fields, dict)
     except:
         message = 'incoming websocket message was not a json object: {}'.format(message.data)
         log.error(message)
         self.send(error=message)
     else:
         log.debug('received {}', fields)
         responder.defer(self, fields)
Пример #25
0
    def check_authentication(cls):
        host, origin = cherrypy.request.headers[
            'host'], cherrypy.request.headers['origin']
        if ('//' + host.split(':')[0]) not in origin:
            log.error(
                'Javascript websocket connections must follow same-origin policy; origin {!r} does not match host {!r}',
                origin, host)
            raise WebSocketAuthError('Origin and Host headers do not match')

        if config['ws.auth_required'] and not cherrypy.session.get(
                config['ws.auth_field']):
            log.warning(
                'websocket connections to this address must have a valid session'
            )
            raise WebSocketAuthError('You are not logged in')

        return WebSocketDispatcher.check_authentication()
Пример #26
0
def mainloop_daemon():
    log.info('starting Sideboard daemon process')
    args = parser.parse_args()
    if os.fork() == 0:
        pid = os.fork()
        if pid == 0:
            mainloop()
        else:
            log.debug('writing pid ({}) to pidfile ({})', pid, args.pidfile)
            try:
                with open(args.pidfile, 'w') as f:
                    f.write('{}'.format(pid))
            except:
                log.error('unexpected error writing pid ({}) to pidfile ({})',
                          pid,
                          args.pidfile,
                          exc_info=True)
Пример #27
0
    def subscribe(self, callback, method, *args, **kwargs):
        """
        Send a websocket request which you expect to subscribe you to a channel
        with a callback which will be called every time there is new data, and
        return the client id which uniquely identifies this subscription.

        Callback may be either a function or a dictionary in the form
        {
            'callback': <function>,
            'errback': <function>,   # optional
            'paramback: <function>,  # optional
            'client': <string>       # optional
        }
        Both callback and errback take a single argument; for callback, this is
        the return value of the method, for errback it is the error message
        returning.  If no errback is specified, we will log errors at the ERROR
        level and do nothing further.

        The paramback function exists for subscriptions where we might want to
        pass different parameters every time we reconnect.  This might be used
        for e.g. time-based parameters.  This function takes no arguments and
        returns the parameters which should be passed every time we connect
        and fire (or re-fire) all of our subscriptions.

        The client id is automatically generated if omitted, and you should not
        set this yourself unless you really know what you're doing.

        The positional and keyword arguments passed to this function will be
        used as the arguments to the remote method, unless paramback is passed,
        in which case that will be used to generate the params, and args/kwargs
        will be ignored.
        """
        client = self._next_id('client')
        if isinstance(callback, Mapping):
            assert 'callback' in callback, 'callback is required'
            client = callback.setdefault('client', client)
            self._callbacks[client] = callback
        else:
            self._callbacks[client] = {'client': client, 'callback': callback}

        paramback = self._callbacks[client].get('paramback')
        params = self.preprocess(
            method,
            paramback() if paramback else (args or kwargs))
        self._callbacks[client].setdefault(
            'errback',
            lambda result: log.error('{}(*{}, **{}) returned an error: {!r}',
                                     method, args, kwargs, result))
        self._callbacks[client].update({'method': method, 'params': params})

        try:
            self._send(method=method, params=params, client=client)
        except:
            log.warn(
                'initial subscription to {} at {!r} failed, will retry on reconnect',
                method, self.url)

        return client
Пример #28
0
    def subscribe(self, callback, method, *args, **kwargs):
        """
        Send a websocket request which you expect to subscribe you to a channel
        with a callback which will be called every time there is new data, and
        return the client id which uniquely identifies this subscription.

        Callback may be either a function or a dictionary in the form
        {
            'callback': <function>,
            'errback': <function>,   # optional
            'paramback: <function>,  # optional
            'client': <string>       # optional
        }
        Both callback and errback take a single argument; for callback, this is
        the return value of the method, for errback it is the error message
        returning.  If no errback is specified, we will log errors at the ERROR
        level and do nothing further.

        The paramback function exists for subscriptions where we might want to
        pass different parameters every time we reconnect.  This might be used
        for e.g. time-based parameters.  This function takes no arguments and
        returns the parameters which should be passed every time we connect
        and fire (or re-fire) all of our subscriptions.

        The client id is automatically generated if omitted, and you should not
        set this yourself unless you really know what you're doing.

        The positional and keyword arguments passed to this function will be
        used as the arguments to the remote method, unless paramback is passed,
        in which case that will be used to generate the params, and args/kwargs
        will be ignored.
        """
        client = self._next_id('client')
        if isinstance(callback, Mapping):
            assert 'callback' in callback, 'callback is required'
            client = callback.setdefault('client', client)
            self._callbacks[client] = callback
        else:
            self._callbacks[client] = {
                'client': client,
                'callback': callback
            }

        paramback = self._callbacks[client].get('paramback')
        params = self.preprocess(method, paramback() if paramback else (args or kwargs))
        self._callbacks[client].setdefault('errback', lambda result: log.error('{}(*{}, **{}) returned an error: {!r}', method, args, kwargs, result))
        self._callbacks[client].update({
            'method': method,
            'params': params
        })

        try:
            self._send(method=method, params=params, client=client)
        except:
            log.warn('initial subscription to {} at {!r} failed, will retry on reconnect', method, self.url)

        return client
Пример #29
0
def _make_jsonrpc_handler(
    services,
    debug=config["debug"],
    precall=lambda body: None,
    errback=lambda err, message: log.error(message, exc_info=True),
):
    @cherrypy.expose
    @cherrypy.tools.force_json_in()
    @cherrypy.tools.json_out(handler=json_handler)
    def jsonrpc_handler(self):
        id = None

        def error(code, message):
            body = {"jsonrpc": "2.0", "id": id, "error": {"code": code, "message": message}}
            log.warn("returning error message: {!r}", body)
            return body

        body = cherrypy.request.json
        if not isinstance(body, dict):
            return error(ERR_INVALID_JSON, "invalid json input {!r}".format(cherrypy.request.body))

        log.debug("jsonrpc request body: {!r}", body)

        id, params = body.get("id"), body.get("params", [])
        if "method" not in body:
            return error(ERR_INVALID_RPC, '"method" field required for jsonrpc request')

        method = body["method"]
        if method.count(".") != 1:
            return error(ERR_MISSING_FUNC, "invalid method " + method)

        module, function = method.split(".")
        if module not in services:
            return error(ERR_MISSING_FUNC, "no module " + module)

        service = services[module]
        if not hasattr(service, function):
            return error(ERR_MISSING_FUNC, "no function " + method)

        if not isinstance(params, (list, dict)):
            return error(ERR_INVALID_PARAMS, "invalid parameter list: {!r}".format(params))

        args, kwargs = (params, {}) if isinstance(params, list) else ([], params)

        precall(body)
        try:
            response = {"jsonrpc": "2.0", "id": id, "result": getattr(service, function)(*args, **kwargs)}
            log.debug("returning success message: {!r}", response)
            return response
        except Exception as e:
            errback(e, "unexpected jsonrpc error calling " + method)
            message = "unexpected error"
            if debug:
                message += ": " + traceback.format_exc()
            return error(ERR_FUNC_EXCEPTION, message)

    return jsonrpc_handler
Пример #30
0
 def handle_message(self, message):
     """
     Given a message dictionary, perform the relevant RPC actions and send
     out the response.  This function is called from a pool of background
     threads
     """
     before = time.time()
     duration, result = None, None
     threadlocal.reset(websocket=self,
                       message=message,
                       headers=self.header_fields,
                       **self.session_fields)
     action, callback, client, method = message.get('action'), message.get(
         'callback'), message.get('client'), message.get('method')
     try:
         with self.client_lock(client):
             self.internal_action(action, client, callback)
             if method:
                 self.clear_cached_response(client, callback)
                 func = self.get_method(method)
                 args, kwargs = get_params(message.get('params'))
                 result = self.NO_RESPONSE
                 try:
                     result = func(*args, **kwargs)
                     duration = (time.time() -
                                 before) if config['debug'] else None
                 finally:
                     trigger_delayed_notifications()
                     self.update_triggers(client, callback, func, args,
                                          kwargs, result, duration)
     except:
         log.error('unexpected websocket dispatch error', exc_info=True)
         exc_class, exc, tb = sys.exc_info()
         str_content = str(exc) or 'Unexpected Error.'
         message = (
             str_content + '\n' +
             traceback.format_exc()) if config['debug'] else str_content
         self.send(error=message, callback=callback, client=client)
     else:
         if callback is not None and result is not self.NO_RESPONSE:
             self.send(data=result,
                       callback=callback,
                       client=client,
                       _time=duration)
Пример #31
0
    def differences(cls, instance):
        diff = {}
        for attr, column in instance.__table__.columns.items():
            new_val = getattr(instance, attr)
            old_val = instance.orig_value_of(attr)
            if old_val != new_val:
                """
                Important note: here we try and show the old vs new value for
                something that has been changed so that we can report it in the
                tracking page.

                Sometimes, however, if we changed the type of the value in the
                database (via a database migration) the old value might not be
                able to be shown as the new type (i.e. it used to be a string,
                now it's int).

                In that case, we won't be able to show a representation of the
                old value and instead we'll log it as '<ERROR>'. In theory the
                database migration SHOULD be the thing handling this, but if it
                doesn't, it becomes our problem to deal with.

                We are overly paranoid with exception handling here because the
                tracking code should be made to never, ever, ever crash, even
                if it encounters insane/old data that really shouldn't be our
                problem.
                """
                try:
                    old_val_repr = cls.repr(column, old_val)
                except Exception as e:
                    log.error(
                        'Tracking repr({}) failed on old value'.format(attr),
                        exc_info=True)
                    old_val_repr = '<ERROR>'

                try:
                    new_val_repr = cls.repr(column, new_val)
                except Exception as e:
                    log.error(
                        'Tracking repr({}) failed on new value'.format(attr),
                        exc_info=True)
                    new_val_repr = '<ERROR>'

                diff[attr] = "'{} -> {}'".format(old_val_repr, new_val_repr)
        return diff
Пример #32
0
 def received_message(self, message):
     """
     This overrides the default ws4py event handler to parse the incoming
     message and pass it off to our pool of background threads, which call
     this class' handle_message function to perform the relevant RPC actions.
     """
     try:
         data = message.data if isinstance(
             message.data, six.text_type) else message.data.decode('utf-8')
         fields = json.loads(data)
         assert isinstance(fields, dict)
     except:
         message = 'incoming websocket message was not a json object: {}'.format(
             message.data)
         log.error(message)
         self.send(error=message)
     else:
         log.debug('received {}', fields)
         responder.defer(self, fields)
Пример #33
0
    def _status_adjustments(self):
        if self.badge_status == c.NEW_STATUS and self.banned:
            self.badge_status = c.WATCHED_STATUS
            try:
                send_email(c.SECURITY_EMAIL,
                           [c.REGDESK_EMAIL, c.SECURITY_EMAIL],
                           c.EVENT_NAME + ' WatchList Notification',
                           render('emails/reg_workflow/attendee_watchlist.txt',
                                  {'attendee': self}),
                           model='n/a')
            except:
                log.error('unable to send banned email about {}', self)

        elif self.badge_status == c.NEW_STATUS and not self.placeholder and \
                self.first_name and (
                    self.paid in [c.HAS_PAID, c.NEED_NOT_PAY] or
                    self.paid == c.PAID_BY_GROUP and
                    self.group_id and
                    not self.group.is_unpaid):
            self.badge_status = c.COMPLETED_STATUS
Пример #34
0
def ldap_auth(username, password):
    if not username or not password:
        return False

    try:
        conn = ldap.initialize(config['ldap.url'])

        force_start_tls = False
        if config['ldap.cacert']:
            ldap.set_option(ldap.OPT_X_TLS_CACERTFILE, config['ldap.cacert'])
            force_start_tls = True

        if config['ldap.cert']:
            ldap.set_option(ldap.OPT_X_TLS_CERTFILE, config['ldap.cert'])
            force_start_tls = True

        if config['ldap.key']:
            ldap.set_option(ldap.OPT_X_TLS_KEYFILE, config['ldap.key'])
            force_start_tls = True

        if force_start_tls:
            conn.start_tls_s()
        else:
            conn.set_option(ldap.OPT_X_TLS_DEMAND, config['ldap.start_tls'])
    except:
        log.error('Error initializing LDAP connection', exc_info=True)
        raise

    for basedn in listify(config['ldap.basedn']):
        dn = '{}={},{}'.format(config['ldap.userattr'], username, basedn)
        log.debug('attempting to bind with dn {}', dn)
        try:
            conn.simple_bind_s(dn, password)
        except ldap.INVALID_CREDENTIALS as x:
            continue
        except:
            log.warning("Error binding to LDAP server with dn", exc_info=True)
            raise
        else:
            return True
Пример #35
0
def ldap_auth(username, password):
    if not username or not password:
        return False
    
    try:
        conn = ldap.initialize(config['ldap.url'])
        
        force_start_tls = False
        if config['ldap.cacert']:
            ldap.set_option(ldap.OPT_X_TLS_CACERTFILE, config['ldap.cacert'])
            force_start_tls = True
            
        if config['ldap.cert']:
            ldap.set_option(ldap.OPT_X_TLS_CERTFILE, config['ldap.cert'])
            force_start_tls = True
            
        if config['ldap.key']:
            ldap.set_option(ldap.OPT_X_TLS_KEYFILE, config['ldap.key'])
            force_start_tls = True
    
        if force_start_tls:
            conn.start_tls_s()
        else:
            conn.set_option(ldap.OPT_X_TLS_DEMAND, config['ldap.start_tls'])
    except:
        log.error('Error initializing LDAP connection', exc_info=True)
        raise
    
    for basedn in listify(config['ldap.basedn']):
        dn = '{}={},{}'.format(config['ldap.userattr'], username, basedn)
        log.debug('attempting to bind with dn {}', dn)
        try:
            conn.simple_bind_s(dn, password)
        except ldap.INVALID_CREDENTIALS as x:
            continue
        except:
            log.warning("Error binding to LDAP server with dn", exc_info=True)
            raise
        else:
            return True
Пример #36
0
 def handle_message(self, message):
     before = time.time()
     duration, result = None, None
     threadlocal.reset(websocket=self,
                       message=message,
                       username=self.username)
     action, callback, client, method = message.get('action'), message.get(
         'callback'), message.get('client'), message.get('method')
     try:
         with self.client_lock(client):
             self.internal_action(action, client, callback)
             if method:
                 func = self.get_method(method)
                 args, kwargs = get_params(message.get('params'))
                 result = self.NO_RESPONSE
                 try:
                     result = func(*args, **kwargs)
                     duration = (time.time() -
                                 before) if config['debug'] else None
                 finally:
                     self.update_triggers(client, callback, func, args,
                                          kwargs, result, duration)
     except:
         log.error('unexpected websocket dispatch error', exc_info=True)
         exc_class, exc, tb = sys.exc_info()
         str_content = str(exc) or 'Unexpected Error.'
         message = (
             str_content + '\n' +
             traceback.format_exc()) if config['debug'] else str_content
         self.send(error=message, callback=callback, client=client)
     else:
         if callback is not None and result is not self.NO_RESPONSE:
             self.send(data=result,
                       callback=callback,
                       client=client,
                       _time=duration)
Пример #37
0
 def subscribe(self, callback, method, *args, **kwargs):
     """
     Send a websocket request which you expect to subscribe you to a channel
     with a callback which will be called every time there is new data, and
     return the client id which uniquely identifies this subscription.
     
     Callback may be either a function or a dictionary in the form
     {
         'callback': <function>,
         'errback': <function>
     }
     Both callback and errback take a single argument; for callback, this is
     the return value of the method, for errback it is the error message
     returning.  If no errback is specified, we will log errors at the ERROR
     level and do nothing further.
     
     The positional and keyword arguments passed to this function will be
     used as the arguments to the remote method.
     """
     client = self._next_id('client')
     if isinstance(callback, dict):
         assert 'callback' in callback and 'errback' in callback, 'callback and errback are required'
         client = callback.setdefault('client', client)
         self._callbacks[client] = callback
     else:
         self._callbacks[client] = {
             'client': client,
             'callback': callback,
             'errback': lambda result: log.error('{}(*{}, **{}) returned an error: {!r}', method, args, kwargs, result)
         }
     self._callbacks[client].update({
         'method': method,
         'params': args or kwargs
     })
     try:
         self._send(method=method, params=args or kwargs, client=client)
     except:
         log.warn('initial subscription to {} at {!r} failed, will retry on reconnect', method, self.url)
     return client
Пример #38
0
 def subscribe(self, callback, method, *args, **kwargs):
     """
     Send a websocket request which you expect to subscribe you to a channel
     with a callback which will be called every time there is new data, and
     return the client id which uniquely identifies this subscription.
     
     Callback may be either a function or a dictionary in the form
     {
         'callback': <function>,
         'errback': <function>
     }
     Both callback and errback take a single argument; for callback, this is
     the return value of the method, for errback it is the error message
     returning.  If no errback is specified, we will log errors at the ERROR
     level and do nothing further.
     
     The positional and keyword arguments passed to this function will be
     used as the arguments to the remote method.
     """
     client = self._next_id('client')
     if isinstance(callback, Mapping):
         assert 'callback' in callback and 'errback' in callback, 'callback and errback are required'
         client = callback.setdefault('client', client)
         self._callbacks[client] = callback
     else:
         self._callbacks[client] = {
             'client': client,
             'callback': callback,
             'errback': lambda result: log.error('{}(*{}, **{}) returned an error: {!r}', method, args, kwargs, result)
         }
     self._callbacks[client].update({
         'method': method,
         'params': args or kwargs
     })
     try:
         self._send(method=method, params=args or kwargs, client=client)
     except:
         log.warn('initial subscription to {} at {!r} failed, will retry on reconnect', method, self.url)
     return client
Пример #39
0
 def __del__(self):
     if self.session.transaction._connections:
         log.error('SessionManager went out of scope without underlying connection being closed; did you forget to use it as a context manager?')
         self.session.close()
Пример #40
0
 def __del__(self):
     if self.session.transaction._connections:
         log.error(
             'SessionManager went out of scope without underlying connection being closed; did you forget to use it as a context manager?'
         )
         self.session.close()
Пример #41
0
def _make_jsonrpc_handler(
    services,
    debug=config['debug'],
    precall=lambda body: None,
    errback=lambda err, message: log.error(message, exc_info=True)):
    @cherrypy.expose
    @cherrypy.tools.force_json_in()
    @cherrypy.tools.json_out(handler=json_handler)
    def jsonrpc_handler(self=None):
        id = None

        def error(code, message):
            body = {
                'jsonrpc': '2.0',
                'id': id,
                'error': {
                    'code': code,
                    'message': message
                }
            }
            log.warn('returning error message: {!r}', body)
            return body

        body = cherrypy.request.json
        if not isinstance(body, dict):
            return error(
                ERR_INVALID_JSON,
                'invalid json input {!r}'.format(cherrypy.request.body))

        log.debug('jsonrpc request body: {!r}', body)

        id, params = body.get('id'), body.get('params', [])
        if 'method' not in body:
            return error(ERR_INVALID_RPC,
                         '"method" field required for jsonrpc request')

        method = body['method']
        if method.count('.') != 1:
            return error(ERR_MISSING_FUNC, 'invalid method ' + method)

        module, function = method.split('.')
        if module not in services:
            return error(ERR_MISSING_FUNC, 'no module ' + module)

        service = services[module]
        if not hasattr(service, function):
            return error(ERR_MISSING_FUNC, 'no function ' + method)

        if not isinstance(params, (list, dict)):
            return error(ERR_INVALID_PARAMS,
                         'invalid parameter list: {!r}'.format(params))

        args, kwargs = (params, {}) if isinstance(params, list) else ([],
                                                                      params)

        precall(body)
        try:
            response = {
                'jsonrpc': '2.0',
                'id': id,
                'result': getattr(service, function)(*args, **kwargs)
            }
            log.debug('returning success message: {!r}', response)
            return response
        except Exception as e:
            errback(e, 'unexpected jsonrpc error calling ' + method)
            message = 'unexpected error'
            if debug:
                message += ': ' + traceback.format_exc()
            return error(ERR_FUNC_EXCEPTION, message)
        finally:
            trigger_delayed_notifications()

    return jsonrpc_handler