Beispiel #1
0
    async def open(self, path, *args, **kwargs):
        _, context = _APPS[path]

        token = self._token
        if self.selected_subprotocol != 'bokeh':
            self.close()
            raise ProtocolError("Subprotocol header is not 'bokeh'")
        elif token is None:
            self.close()
            raise ProtocolError("No token received in subprotocol header")

        session_id = get_session_id(token)

        await context.create_session_if_needed(session_id, self.request, token)
        session = context.get_session(session_id)

        try:
            protocol = Protocol()
            self.receiver = Receiver(protocol)
            self.handler = ProtocolHandler()
            self.connection = self.new_connection(protocol, context, session)
        except ProtocolError as e:
            self.close()
            raise e

        msg = self.connection.protocol.create('ACK')
        await self.send_message(msg)
Beispiel #2
0
    async def _async_open(self, token: str) -> None:
        try:
            session_id = get_session_id(token)
            await self.application_context.create_session_if_needed(
                session_id, self.request, token)
            session = self.application_context.get_session(session_id)

            protocol = Protocol()
            self.receiver = Receiver(protocol)
            log.debug("Receiver created for %r", protocol)

            self.handler = ProtocolHandler()
            log.debug("ProtocolHandler created for %r", protocol)

            self.connection = self._new_connection(protocol, self,
                                                   self.application_context,
                                                   session)
            log.info("ServerConnection created")

        except Exception as e:
            log.error("Could not create new server session, reason: %s", e)
            self.close()
            raise e

        msg = self.connection.protocol.create('ACK')
        await self._send_bokeh_message(msg)
Beispiel #3
0
    async def get_session(self):
        token = self.get_argument("bokeh-token", default=None)
        session_id = self.get_argument("bokeh-session-id", default=None)
        if 'Bokeh-Session-Id' in self.request.headers:
            if session_id is not None:
                log.debug("Server received session ID in request argument and header, expected only one")
                raise HTTPError(status_code=403, reason="session ID was provided as an argument and header")
            session_id = self.request.headers.get('Bokeh-Session-Id')

        if token is not None:
            if session_id is not None:
                log.debug("Server received both token and session ID, expected only one")
                raise HTTPError(status_code=403, reason="Both token and session ID were provided")
            session_id = get_session_id(token)
        elif session_id is None:
            if self.application.generate_session_ids:
                session_id = generate_session_id(secret_key=self.application.secret_key,
                                                 signed=self.application.sign_sessions)
            else:
                log.debug("Server configured not to generate session IDs and none was provided")
                raise HTTPError(status_code=403, reason="No bokeh-session-id provided")

        if token is None:
            if self.application.include_headers is None:
                excluded_headers = (self.application.exclude_headers or [])
                allowed_headers = [header for header in self.request.headers
                                   if header not in excluded_headers]
            else:
                allowed_headers = self.application.include_headers
            headers = {k: v for k, v in self.request.headers.items()
                       if k in allowed_headers}

            if self.application.include_cookies is None:
                excluded_cookies = (self.application.exclude_cookies or [])
                allowed_cookies = [cookie for cookie in self.request.cookies
                                   if cookie not in excluded_cookies]
            else:
                allowed_cookies = self.application.include_cookies
            cookies = {k: v.value for k, v in self.request.cookies.items()
                       if k in allowed_cookies}

            payload = {'headers': headers, 'cookies': cookies}
            payload.update(self.application_context.application.process_request(self.request))
            token = generate_jwt_token(session_id,
                                       secret_key=self.application.secret_key,
                                       signed=self.application.sign_sessions,
                                       expiration=self.application.session_token_expiration,
                                       extra_payload=payload)

        if not check_token_signature(token,
                                     secret_key=self.application.secret_key,
                                     signed=self.application.sign_sessions):
            log.error("Session id had invalid signature: %r", session_id)
            raise HTTPError(status_code=403, reason="Invalid token or session ID")

        session = await self.application_context.create_session_if_needed(session_id, self.request, token)

        return session
Beispiel #4
0
 def test_payload_signed(self):
     session_id = generate_session_id(signed=True, secret_key="abc")
     token = generate_jwt_token(session_id, signed=True, secret_key="abc", extra_payload=dict(foo=10))
     assert '.' in token
     decoded = json.loads(_base64_decode(token.split('.')[0], encoding='utf-8'))
     assert 'session_id' in decoded
     session_id = get_session_id(token)
     assert check_token_signature(token, secret_key="abc", signed=True)
     assert not check_token_signature(token, secret_key="qrs", signed=True)
     assert decoded['foo'] == 10
async def test__request_in_session_context_has_arguments(ManagedServerLoop) -> None:
    application = Application()
    with ManagedServerLoop(application) as server:
        response = await http_get(server.io_loop, url(server) + "?foo=10")
        html = response.body
        token = extract_token_from_json(html)
        sessionid = get_session_id(token)

        server_session = server.get_session('/', sessionid)
        server_doc = server_session.document
        session_context = server_doc.session_context
        # test if we can get the argument from the request
        assert session_context.request.arguments['foo'] == [b'10']
async def test__request_in_session_context(ManagedServerLoop) -> None:
    application = Application()
    with ManagedServerLoop(application) as server:
        response = await http_get(server.io_loop, url(server) + "?foo=10")
        html = response.body
        token = extract_token_from_json(html)
        sessionid = get_session_id(token)

        server_session = server.get_session('/', sessionid)
        server_doc = server_session.document
        session_context = server_doc.session_context
        # do we have a request
        assert session_context.request is not None
async def test__autocreate_session_doc(ManagedServerLoop) -> None:
    application = Application()
    with ManagedServerLoop(application) as server:
        sessions = server.get_sessions('/')
        assert 0 == len(sessions)

        response = await http_get(server.io_loop, url(server))
        html = response.body
        token = extract_token_from_json(html)
        sessionid = get_session_id(token)

        sessions = server.get_sessions('/')
        assert 1 == len(sessions)
        assert sessionid == sessions[0].id
async def test__no_request_arguments_in_session_context(ManagedServerLoop) -> None:
    application = Application()
    with ManagedServerLoop(application) as server:
        response = await http_get(server.io_loop, url(server))
        html = response.body
        token = extract_token_from_json(html)
        sessionid = get_session_id(token)

        server_session = server.get_session('/', sessionid)
        server_doc = server_session.document
        session_context = server_doc.session_context
        # if we do not pass any arguments to the url, the request arguments
        # should be empty
        assert len(session_context.request.arguments) == 0
async def test__autocreate_signed_session_autoload(ManagedServerLoop) -> None:
    application = Application()
    with ManagedServerLoop(application, sign_sessions=True, secret_key='foo') as server:
        sessions = server.get_sessions('/')
        assert 0 == len(sessions)

        response = await http_get(server.io_loop, autoload_url(server))
        js = response.body
        token = extract_token_from_json(js)
        sessionid = get_session_id(token)

        sessions = server.get_sessions('/')
        assert 1 == len(sessions)
        assert sessionid == sessions[0].id

        assert check_token_signature(token, signed=True, secret_key='foo')
async def test__use_provided_session_doc(ManagedServerLoop) -> None:
    application = Application()
    with ManagedServerLoop(application) as server:
        sessions = server.get_sessions('/')
        assert 0 == len(sessions)

        expected = 'foo'
        response = await http_get(server.io_loop, url(server) + "?bokeh-session-id=" + expected)
        html = response.body
        token = extract_token_from_json(html)
        sessionid = get_session_id(token)
        assert expected == sessionid

        sessions = server.get_sessions('/')
        assert 1 == len(sessions)
        assert expected == sessions[0].id
async def test__use_provided_session_header_autoload(ManagedServerLoop) -> None:
    application = Application()
    with ManagedServerLoop(application) as server:
        sessions = server.get_sessions('/')
        assert 0 == len(sessions)

        expected = 'foo'
        response = await http_get(server.io_loop, autoload_url(server), headers={'Bokeh-Session-Id': expected})
        js = response.body
        token = extract_token_from_json(js)
        sessionid = get_session_id(token)
        assert expected == sessionid

        sessions = server.get_sessions('/')
        assert 1 == len(sessions)
        assert expected == sessions[0].id
Beispiel #12
0
 def test_payload_signed(self):
     session_id = generate_session_id(signed=True, secret_key="abc")
     token = generate_jwt_token(session_id,
                                signed=True,
                                secret_key="abc",
                                extra_payload=dict(foo=10))
     assert '.' in token
     decoded = json.loads(_b64_to_utf8(token.split('.')[0]))
     assert _TOKEN_ZLIB_KEY in decoded
     assert 'session_id' in decoded
     session_id = get_session_id(token)
     assert check_token_signature(token, secret_key="abc", signed=True)
     assert not check_token_signature(token, secret_key="qrs", signed=True)
     payload = get_token_payload(token)
     assert _TOKEN_ZLIB_KEY not in payload
     assert payload['foo'] == 10
Beispiel #13
0
    async def _async_open(self, token):
        ''' Perform the specific steps needed to open a connection to a Bokeh session

        Specifically, this method coordinates:

        * Getting a session for a session ID (creating a new one if needed)
        * Creating a protocol receiver and handler
        * Opening a new ServerConnection and sending it an ACK

        Args:
            session_id (str) :
                A session ID to for a session to connect to

                If no session exists with the given ID, a new session is made

        Returns:
            None

        '''
        try:
            session_id = get_session_id(token)
            await self.application_context.create_session_if_needed(
                session_id, self.request, token)
            session = self.application_context.get_session(session_id)

            protocol = Protocol()
            self.receiver = Receiver(protocol)
            log.debug("Receiver created for %r", protocol)

            self.handler = ProtocolHandler()
            log.debug("ProtocolHandler created for %r", protocol)

            self.connection = self.application.new_connection(
                protocol, self, self.application_context, session)
            log.info("ServerConnection created")

        except ProtocolError as e:
            log.error("Could not create new server session, reason: %s", e)
            self.close()
            raise e

        msg = self.connection.protocol.create('ACK')
        await self.send_message(msg)

        return None
async def test__use_provided_session_autoload_token(ManagedServerLoop) -> None:
    application = Application()
    with ManagedServerLoop(application) as server:
        sessions = server.get_sessions('/')
        assert 0 == len(sessions)

        expected = 'foo'
        expected_token = generate_jwt_token(expected)
        response = await http_get(server.io_loop, autoload_url(server) + "&bokeh-token=" + expected_token)
        js = response.body
        token = extract_token_from_json(js)
        assert expected_token == token
        sessionid = get_session_id(token)
        assert expected == sessionid

        sessions = server.get_sessions('/')
        assert 1 == len(sessions)
        assert expected == sessions[0].id
Beispiel #15
0
    async def connect(self):
        log.info('WebSocket connection opened')

        subprotocols = self.scope["subprotocols"]
        if len(subprotocols) != 2 or subprotocols[0] != 'bokeh':
            self.close()
            raise RuntimeError("Subprotocol header is not 'bokeh'")

        token = subprotocols[1]
        if token is None:
            self.close()
            raise RuntimeError("No token received in subprotocol header")

        now = calendar.timegm(dt.datetime.now().utctimetuple())
        payload = get_token_payload(token)
        if 'session_expiry' not in payload:
            self.close()
            raise RuntimeError("Session expiry has not been provided")
        elif now >= payload['session_expiry']:
            self.close()
            raise RuntimeError("Token is expired.")
        elif not check_token_signature(token,
                                       signed=False,
                                       secret_key=None):
            session_id = get_session_id(token)
            log.error("Token for session %r had invalid signature", session_id)
            raise RuntimeError("Invalid token signature")

        def on_fully_opened(future):
            e = future.exception()
            if e is not None:
                # this isn't really an error (unless we have a
                # bug), it just means a client disconnected
                # immediately, most likely.
                log.debug("Failed to fully open connlocksection %r", e)

        future = self._async_open(token)

        # rewrite above line using asyncio
        # this task is scheduled to run soon once context is back to event loop
        task = asyncio.ensure_future(future)
        task.add_done_callback(on_fully_opened)
        await self.accept("bokeh")
Beispiel #16
0
    def open(self):
        ''' Initialize a connection to a client.

        Returns:
            None

        '''
        log.info('WebSocket connection opened')
        token = self._token

        if self.selected_subprotocol != 'bokeh':
            self.close()
            raise ProtocolError("Subprotocol header is not 'bokeh'")
        elif token is None:
            self.close()
            raise ProtocolError("No token received in subprotocol header")

        now = calendar.timegm(dt.datetime.utcnow().utctimetuple())
        payload = get_token_payload(token)
        if 'session_expiry' not in payload:
            self.close()
            raise ProtocolError("Session expiry has not been provided")
        elif now >= payload['session_expiry']:
            self.close()
            raise ProtocolError("Token is expired.")
        elif not check_token_signature(token,
                                       signed=self.application.sign_sessions,
                                       secret_key=self.application.secret_key):
            session_id = get_session_id(token)
            log.error("Token for session %r had invalid signature", session_id)
            raise ProtocolError("Invalid token signature")

        try:
            self.application.io_loop.spawn_callback(self._async_open,
                                                    self._token)
        except Exception as e:
            # this isn't really an error (unless we have a
            # bug), it just means a client disconnected
            # immediately, most likely.
            log.debug("Failed to fully open connection %r", e)