예제 #1
0
 def send(self, data):
     log.debug('sending {!r}', data)
     assert self.connected, 'tried to send data on closed websocket {!r}'.format(
         self.url)
     if isinstance(data, Mapping):
         data = json.dumps(data)
     return WebSocketClient.send(self, data)
예제 #2
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)
예제 #3
0
 def received_message(self, message):
     message = message.data if isinstance(message.data, six.text_type) else message.data.decode('utf-8')
     log.debug('received {!r}', message)
     try:
         message = json.loads(message)
     except:
         log.debug('failed to parse incoming message', exc_info=True)
     finally:
         self.dispatcher.defer(message)
예제 #4
0
 def _dispatch(self, message):
     log.debug('dispatching {}', message)
     assert 'client' in message or 'callback' in message, 'no callback or client in message {}'.format(message)
     id = message.get('client') or message.get('callback')
     assert id in self._callbacks, 'unknown dispatchee {}'.format(id)
     if 'error' in message:
         self._callbacks[id]['errback'](message['error'])
     else:
         self._callbacks[id]['callback'](message.get('data'))
예제 #5
0
 def received_message(self, message):
     message = str(message)
     log.debug('received {!r}', message)
     try:
         message = json.loads(message)
     except:
         log.debug('failed to parse incoming message', exc_info=True)
     finally:
         self.dispatcher.defer(message)
예제 #6
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.warn('failed to send {!r} on {!r}, closing websocket and will attempt to reconnect', kwargs, self.url)
             self.ws.close()
             raise
예제 #7
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
예제 #8
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)
예제 #9
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)
예제 #10
0
파일: jsonrpc.py 프로젝트: ftobia/sideboard
    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)
예제 #11
0
 def _dispatch(self, message):
     log.debug('dispatching {}', message)
     try:
         assert isinstance(message, Mapping), 'incoming message is not a dictionary'
         assert 'client' in message or 'callback' in message, 'no callback or client in message {}'.format(message)
         id = message.get('client') or message.get('callback')
         assert id in self._callbacks, 'unknown dispatchee {}'.format(id)
     except AssertionError:
         self.fallback(message)
     else:
         if 'error' in message:
             self._callbacks[id]['errback'](message['error'])
         else:
             self._callbacks[id]['callback'](message.get('data'))
예제 #12
0
 def _dispatch(self, message):
     log.debug('dispatching {}', message)
     try:
         assert isinstance(message, Mapping), 'incoming message is not a dictionary'
         assert 'client' in message or 'callback' in message, 'no callback or client in message {}'.format(message)
         id = message.get('client') or message.get('callback')
         assert id in self._callbacks, 'unknown dispatchee {}'.format(id)
     except AssertionError:
         self.fallback(message)
     else:
         if 'error' in message:
             self._callbacks[id]['errback'](message['error'])
         else:
             self._callbacks[id]['callback'](message.get('data'))
예제 #13
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)
예제 #14
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)
예제 #15
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
예제 #16
0
    def send(self, **message):
        message = {k: v for k, v in message.items() if v is not None}
        if 'data' in message and 'client' in message:
            fingerprint = _fingerprint(message['data'])
            client, callback = message['client'], message.get('callback')
            repeat_send = callback in self.cached_fingerprints[client]
            cached_fingerprint = self.cached_fingerprints[client].get(callback)
            self.cached_fingerprints[client][callback] = fingerprint
            if cached_fingerprint == fingerprint and repeat_send:
                return

        log.debug('sending {}', message)
        message = json.dumps(message, cls=sideboard.lib.serializer,
                                      separators=(',', ':'), sort_keys=True)
        with self.send_lock:
            WebSocket.send(self, message)
예제 #17
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)
예제 #18
0
    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)
예제 #19
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)
예제 #20
0
    def send(self, **message):
        message = {k: v for k, v in message.items() if v is not None}
        if 'data' in message and 'client' in message:
            fingerprint = _fingerprint(message['data'])
            client, callback = message['client'], message.get('callback')
            repeat_send = callback in self.cached_fingerprints[client]
            cached_fingerprint = self.cached_fingerprints[client].get(callback)
            self.cached_fingerprints[client][callback] = fingerprint
            if cached_fingerprint == fingerprint and repeat_send:
                return

        log.debug('sending {}', message)
        message = json.dumps(message,
                             cls=sideboard.lib.serializer,
                             separators=(',', ':'),
                             sort_keys=True)
        with self.send_lock:
            WebSocket.send(self, message)
예제 #21
0
    def send(self, **message):
        """
        This overrides the ws4py-provided send to implement three new features:

        1) Instead of taking a string, this method treats its keyword arguments
           as the message, serializes them to JSON, and sends that.

        2) For subscription responses, we keep track of the most recent response
           we sent for the given subscription.  If neither the request or
           response have changed since the last time we pushed data back to the
           client for this subscription, we don't send anything.

        3) We lock when sending to ensure that our sends are thread-safe.
           Surprisingly, the "ws4py.threadedclient" class isn't thread-safe!

        4) Subscriptions firing will sometimes trigger a send on a websocket
           which has already been marked as closed.  When this happens we log a
           debug message and then exit without error.
        """
        if self.is_closed:
            log.debug('ignoring send on an already closed websocket: {}',
                      message)
            self.unsubscribe_all()
            return

        message = {k: v for k, v in message.items() if v is not None}
        if 'data' in message and 'client' in message:
            fingerprint = _fingerprint(message['data'])
            client, callback = message['client'], message.get('callback')
            repeat_send = callback in self.cached_fingerprints[client]
            cached_fingerprint = self.cached_fingerprints[client].get(callback)
            self.cached_fingerprints[client][callback] = fingerprint
            if cached_fingerprint == fingerprint and repeat_send:
                return

        log.debug('sending {}', message)
        message = json.dumps(message,
                             cls=sideboard.lib.serializer,
                             separators=(',', ':'),
                             sort_keys=True)
        with self.send_lock:
            if not self.is_closed:
                WebSocket.send(self, message)
예제 #22
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)
예제 #23
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
예제 #24
0
    def send(self, **message):
        """
        This overrides the ws4py-provided send to implement three new features:

        1) Instead of taking a string, this method treats its keyword arguments
           as the message, serializes them to JSON, and sends that.

        2) For subscription responses, we keep track of the most recent response
           we sent for the given subscription.  If neither the request or
           response have changed since the last time we pushed data back to the
           client for this subscription, we don't send anything.

        3) We lock when sending to ensure that our sends are thread-safe.
           Surprisingly, the "ws4py.threadedclient" class isn't thread-safe!

        4) Subscriptions firing will sometimes trigger a send on a websocket
           which has already been marked as closed.  When this happens we log a
           debug message and then exit without error.
        """
        if self.is_closed:
            log.debug('ignoring send on an already closed websocket: {}', message)
            self.unsubscribe_all()
            return

        message = {k: v for k, v in message.items() if v is not None}
        if 'data' in message and 'client' in message:
            fingerprint = _fingerprint(message['data'])
            client, callback = message['client'], message.get('callback')
            repeat_send = callback in self.cached_fingerprints[client]
            cached_fingerprint = self.cached_fingerprints[client].get(callback)
            self.cached_fingerprints[client][callback] = fingerprint
            if cached_fingerprint == fingerprint and repeat_send:
                return

        log.debug('sending {}', message)
        message = json.dumps(message, cls=sideboard.lib.serializer,
                                      separators=(',', ':'), sort_keys=True)
        with self.send_lock:
            if not self.is_closed:
                WebSocket.send(self, message)
예제 #25
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
예제 #26
0
파일: test_sa.py 프로젝트: ftobia/sideboard
 def test_omit_keys_that_are_returned_by_default(self):
     results = Session.crud.read({'_model': 'Account'}, {
         '_model': False,
         'id': False,
         'username': True,
         'password': False,
         'user': {
             '_model': False,
             'id': False,
             'name': True
         }
     })
     for account in results['results']:
         log.debug('account: {}', account)
         self.assertNotIn('_model', account)
         self.assertNotIn('id', account)
         self.assertNotIn('password', account)
         self.assertNotIn('_model', account['user'])
         self.assertNotIn('id', account['user'])
         
         self.assertIn('username', account)
         self.assertIn('name', account['user'])
예제 #27
0
 def crud_method(*args, **kwargs):
     log.debug('mocked crud.{}'.format(name))
     assert not getattr(self.mr, name + '_error', False)
     return uuid4().hex
예제 #28
0
 def index(self):
     log.debug("this data will be used to render a template")
     return {"plugin": "drafts-as-a-service", "header": True}
예제 #29
0
 def poll(self):
     """empty method which exists only to help keep WebSockets alive"""
     log.debug('sideboard.poll by user {}', threadlocal.get('username'))
예제 #30
0
    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()
예제 #31
0
 def send(self, data):
     log.debug('sending {!r}', data)
     assert self.connected, 'tried to send data on closed websocket {!r}'.format(self.url)
     if isinstance(data, dict):
         data = json.dumps(data)
     return WebSocketClient.send(self, data)
예제 #32
0
 def crud_method(*args, **kwargs):
     log.debug('mocked crud.{}'.format(name))
     assert not getattr(self.mr, name + '_error', False)
     return uuid4().hex