Exemple #1
0
 def __init__(self,
              key,
              gateway_middleware=None,
              client_info=None,
              auth_info=None,
              session_max_time=3600,
              **kwargs):
     Session.last_id += 1
     self.id = Session.last_id
     self.key = key
     self.client_info = client_info or {}
     self.data = {}
     self.identity = None
     self.auth_info = auth_info
     self.touch()
     self.active = True
     logging.info(
         'Opening a new worker gate for session %s, client %s',
         self.id,
         self.client_info['address'],
     )
     self.gate = WorkerGate(self,
                            gateway_middleware=gateway_middleware,
                            name='session %i' % self.id,
                            log_tag='worker',
                            **kwargs)
     self.session_max_time = session_max_time
     self.gate.start()
     logging.debug('New session %s', self.id)
Exemple #2
0
 def __init__(self, context):
     self.context = context
     self.sessions = {}
     self.restricted_gate = WorkerGate(self,
                                       restricted=True,
                                       name='restricted session',
                                       log_tag='restricted')
     self.restricted_gate.start()
Exemple #3
0
class Session(object):
    """
    Holds the HTTP session data
    """

    last_id = 0

    def __init__(self, key, client_info=None, **kwargs):
        Session.last_id += 1
        self.id = Session.last_id
        self.key = key
        self.client_info = client_info or {}
        self.data = {}
        self.identity = None
        self.touch()
        self.active = True
        logging.info(
            'Opening a new worker gate for session %s, client %s',
            self.id,
            self.client_info['address'],
        )
        self.gate = WorkerGate(self,
                               name='session %i' % self.id,
                               log_tag='worker',
                               **kwargs)
        self.gate.start()
        logging.debug('New session %s', self.id)

    def destroy(self):
        logging.debug('Destroying session %s', self.id)
        self.gate.stop()

    def deactivate(self):
        """
        Marks this session as dead
        """
        self.active = False

    def touch(self):
        """
        Updates the "last used" timestamp
        """
        self.timestamp = time.time()

    def is_dead(self):
        return not self.active or (time.time() - self.timestamp) > 3600

    def set_cookie(self, http_context):
        """
        Adds headers to :class:`aj.http.HttpContext` that set
        the session cookie
        """
        cookie = Cookie('session', self.key, path='/',
                        httponly=True).render_response()
        http_context.add_header('Set-Cookie', cookie)
Exemple #4
0
 def __init__(self, context):
     self.context = context
     self.sessions = {}
     self.restricted_gate = WorkerGate(
         self,
         restricted=True,
         name='restricted session',
         log_tag='restricted'
     )
     self.restricted_gate.start()
Exemple #5
0
 def __init__(self, key, gateway_middleware=None, client_info=None, auth_info=None, session_max_time=3600, **kwargs):
     Session.last_id += 1
     self.id = Session.last_id
     self.key = key
     self.client_info = client_info or {}
     self.data = {}
     self.identity = kwargs['initial_identity'] if 'initial_identity' in kwargs.keys() else None
     self.auth_info = auth_info
     self.touch()
     self.active = True
     logging.info(
         f"Opening a new worker gate for session {self.id}, "
         f"client {self.client_info['address']}"
     )
     self.gate = WorkerGate(
         self,
         gateway_middleware=gateway_middleware,
         name=f'session {self.id:d}',
         log_tag='worker',
         **kwargs
     )
     self.session_max_time = session_max_time
     self.gate.start()
     logging.debug(f'New session {self.id}')
Exemple #6
0
 def __init__(self, key, client_info=None, **kwargs):
     Session.last_id += 1
     self.id = Session.last_id
     self.key = key
     self.client_info = client_info or {}
     self.data = {}
     self.identity = None
     self.touch()
     self.active = True
     logging.info(
         'Opening a new worker gate for session %s, client %s',
         self.id,
         self.client_info['address'],
     )
     self.gate = WorkerGate(
         self, name='session %i' % self.id, log_tag='worker', **kwargs
     )
     self.gate.start()
     logging.debug('New session %s', self.id)
Exemple #7
0
class GateMiddleware(object):
    def __init__(self, context):
        self.context = context
        self.sessions = {}
        self.restricted_gate = WorkerGate(self,
                                          gateway_middleware=self,
                                          restricted=True,
                                          name='restricted session',
                                          log_tag='restricted')
        self.restricted_gate.start()

    def generate_session_key(self, env):
        h = str(random.random())
        h += env.get('REMOTE_ADDR', '')
        h += env.get('HTTP_USER_AGENT', '')
        h += env.get('HTTP_HOST', '')
        return hashlib.sha1(h.encode('utf-8')).hexdigest()

    def vacuum(self):
        """
        Eliminates dead sessions
        """
        for session in [x for x in self.sessions.values() if x.is_dead()]:
            session.destroy()
            if session.key in self.sessions:
                del self.sessions[session.key]

    def destroy(self):
        for session in self.sessions.values():
            session.deactivate()
        self.vacuum()

    def open_session(self, env, **kwargs):
        """
        Creates a new session for the :class:`aj.http.HttpContext`
        """
        max_sessions = aj.config.data['max_sessions']
        if max_sessions and len(self.sessions) >= max_sessions:
            candidates = sorted(self.sessions.keys(),
                                key=lambda k: -self.sessions[k].get_age())
            victim = self.sessions[candidates[0]]
            logging.info("Closing session %s due to pool overflow" % victim.id)
            victim.deactivate()
            self.vacuum()

        client_info = {
            'address': env.get('REMOTE_ADDR', None),
        }
        session_key = self.generate_session_key(env)
        session_max_time = aj.config.data['session_max_time']
        session = Session(session_key,
                          gateway_middleware=self,
                          client_info=client_info,
                          session_max_time=session_max_time,
                          **kwargs)
        self.sessions[session_key] = session
        return session

    def obtain_session(self, env):
        cookie_str = env.get('HTTP_COOKIE', None)
        session = None
        if cookie_str:
            cookie = Cookies.from_request(
                cookie_str,
                ignore_bad_cookies=True,
            ).get('session', None)
            if cookie and cookie.value:
                if cookie.value in self.sessions:
                    # Session found
                    session = self.sessions[cookie.value]
                    if session.is_dead():
                        session = None
        return session

    def broadcast_config_data(self):
        self.restricted_gate.send_config_data()
        for session in self.sessions.values():
            if not session.is_dead():
                session.gate.send_config_data()

    def handle(self, http_context):
        start_time = time.time()

        self.vacuum()

        session = self.obtain_session(http_context.env)
        gate = None

        if not session and aj.dev_autologin:
            username = pwd.getpwuid(os.geteuid()).pw_name
            logging.warn('Opening an autologin session for user %s', username)
            session = self.open_session(http_context.env,
                                        initial_identity=username)
            session.set_cookie(http_context)

        if session:
            session.touch()
            gate = session.gate
        else:
            gate = self.restricted_gate

        if http_context.path.startswith('/socket'):
            http_context.fallthrough(SocketIORouteHandler.get(self.context))
            http_context.respond_ok()
            return 'Socket closed'

        request_object = {
            'type': 'http',
            'context': http_context.serialize(),
        }

        # await response

        try:
            timeout = 600
            with Timeout(timeout) as t:
                q = gate.q_http_replies.register()
                rq = gate.stream.send(request_object)
                while True:
                    resp = q.get(t)
                    if resp.id == rq.id:
                        break
        # pylint: disable=E0712
        except Timeout:
            http_context.respond('504 Gateway Timeout')
            return [b'Worker timeout']

        # ---

        if 'error' in resp.object:
            raise WorkerError(resp.object)

        for header in resp.object['headers']:
            http_context.add_header(*header)

        headers = dict(resp.object['headers'])
        if 'X-Session-Redirect' in headers:
            # new authenticated session
            username = headers['X-Session-Redirect']
            logging.info('Opening a session for user %s', username)
            session = self.open_session(
                http_context.env,
                initial_identity=username,
                auth_info=headers['X-Auth-Info'],
            )
            session.set_cookie(http_context)

        http_context.respond(resp.object['status'])
        content = resp.object['content']

        end_time = time.time()
        logging.debug('%.03fs %12s   %s %s %s', end_time - start_time,
                      str_fsize(len(content[0] if content else [])),
                      str(http_context.status).split()[0],
                      http_context.env['REQUEST_METHOD'], http_context.path)

        for index, item in enumerate(content):
            if isinstance(item, six.text_type):
                content[index] = item.encode('utf-8')

        # Touch the session in case system time has dramatically
        # changed during request
        if session:
            session.touch()

        return content
Exemple #8
0
class GateMiddleware(object):
    def __init__(self, context):
        self.context = context
        self.sessions = {}
        self.restricted_gate = WorkerGate(
            self,
            gateway_middleware=self,
            restricted=True,
            name='restricted session',
            log_tag='restricted'
        )
        self.restricted_gate.start()

    def generate_session_key(self, env):
        h = str(random.random())
        h += env.get('REMOTE_ADDR', '')
        h += env.get('HTTP_USER_AGENT', '')
        h += env.get('HTTP_HOST', '')
        return hashlib.sha1(h.encode('utf-8')).hexdigest()

    def vacuum(self):
        """
        Eliminates dead sessions
        """
        for session in [x for x in self.sessions.values() if x.is_dead()]:
            session.destroy()
            if session.key in self.sessions:
                del self.sessions[session.key]

    def destroy(self):
        for session in self.sessions.values():
            session.deactivate()
        self.vacuum()

    def open_session(self, env, **kwargs):
        """
        Creates a new session for the :class:`aj.http.HttpContext`
        """
        max_sessions = aj.config.data['max_sessions']
        if max_sessions and len(self.sessions) >= max_sessions:
            candidates = sorted(self.sessions.keys(), key=lambda k: -self.sessions[k].get_age())
            victim = self.sessions[candidates[0]]
            logging.info("Closing session %s due to pool overflow" % victim.id)
            victim.deactivate()
            self.vacuum()

        client_info = {
            'address': env.get('REMOTE_ADDR', None),
        }
        session_key = self.generate_session_key(env)
        session = Session(session_key, gateway_middleware=self, client_info=client_info, **kwargs)
        self.sessions[session_key] = session
        return session

    def obtain_session(self, env):
        cookie_str = env.get('HTTP_COOKIE', None)
        session = None
        if cookie_str:
            cookie = Cookies.from_request(
                cookie_str,
                ignore_bad_cookies=True,
            ).get('session', None)
            if cookie and cookie.value:
                if cookie.value in self.sessions:
                    # Session found
                    session = self.sessions[cookie.value]
                    if session.is_dead():
                        session = None
        return session

    def broadcast_config_data(self):
        self.restricted_gate.send_config_data()
        for session in self.sessions.values():
            if not session.is_dead():
                session.gate.send_config_data()

    def handle(self, http_context):
        start_time = time.time()

        self.vacuum()

        session = self.obtain_session(http_context.env)
        gate = None

        if not session and aj.dev_autologin:
            username = pwd.getpwuid(os.geteuid()).pw_name
            logging.warn('Opening an autologin session for user %s', username)
            session = self.open_session(
                http_context.env,
                initial_identity=username
            )
            session.set_cookie(http_context)

        if session:
            session.touch()
            gate = session.gate
        else:
            gate = self.restricted_gate

        if http_context.path.startswith('/socket'):
            http_context.fallthrough(SocketIORouteHandler.get(self.context))
            http_context.respond_ok()
            return 'Socket closed'

        request_object = {
            'type': 'http',
            'context': http_context.serialize(),
        }

        # await response

        try:
            timeout = 60
            with Timeout(timeout) as t:
                q = gate.q_http_replies.register()
                rq = gate.stream.send(request_object)
                while True:
                    resp = q.get(t)
                    if resp.id == rq.id:
                        break
        # pylint: disable=E0712
        except Timeout:
            http_context.respond('504 Gateway Timeout')
            return 'Worker timeout'

        # ---

        if 'error' in resp.object:
            raise WorkerError(resp.object)

        for header in resp.object['headers']:
            http_context.add_header(*header)
            if header[0] == 'X-Session-Redirect':
                # new authenticated session
                username = header[1]
                logging.info('Opening a session for user %s', username)
                session = self.open_session(
                    http_context.env,
                    initial_identity=username
                )
                session.set_cookie(http_context)

        http_context.respond(resp.object['status'])
        content = resp.object['content']

        end_time = time.time()
        logging.debug(
            '%.03fs %12s   %s %s %s',
            end_time - start_time,
            str_fsize(len(content[0] if content else [])),
            str(http_context.status).split()[0],
            http_context.env['REQUEST_METHOD'],
            http_context.path
        )

        for index, item in enumerate(content):
            if isinstance(item, six.text_type):
                content[index] = item.encode('utf-8')

        return content
Exemple #9
0
class Session(object):
    """
    Holds the HTTP session data
    """

    last_id = 0

    def __init__(self, key, client_info=None, **kwargs):
        Session.last_id += 1
        self.id = Session.last_id
        self.key = key
        self.client_info = client_info or {}
        self.data = {}
        self.identity = None
        self.touch()
        self.active = True
        logging.info(
            'Opening a new worker gate for session %s, client %s',
            self.id,
            self.client_info['address'],
        )
        self.gate = WorkerGate(
            self, name='session %i' % self.id, log_tag='worker', **kwargs
        )
        self.gate.start()
        logging.debug('New session %s', self.id)

    def destroy(self):
        logging.debug('Destroying session %s', self.id)
        self.gate.stop()

    def deactivate(self):
        """
        Marks this session as dead
        """
        self.active = False

    def touch(self):
        """
        Updates the "last used" timestamp
        """
        self.timestamp = time.time()

    def get_age(self):
        return time.time() - self.timestamp

    def is_dead(self):
        return not self.active or self.get_age() > 3600

    def set_cookie(self, http_context):
        """
        Adds headers to :class:`aj.http.HttpContext` that set
        the session cookie
        """
        cookie = Cookie(
            'session',
            self.key,
            path='/',
            httponly=True
        ).render_response()
        http_context.add_header('Set-Cookie', cookie)
Exemple #10
0
class GateMiddleware(object):
    def __init__(self, context):
        self.context = context
        self.sessions = {}
        self.restricted_gate = WorkerGate(
            self,
            restricted=True,
            name='restricted session',
            log_tag='restricted'
        )
        self.restricted_gate.start()

    def generate_session_key(self, env):
        h = str(random.random())
        h += env.get('REMOTE_ADDR', '')
        h += env.get('HTTP_USER_AGENT', '')
        h += env.get('HTTP_HOST', '')
        return hashlib.sha1(h).hexdigest()

    def vacuum(self):
        """
        Eliminates dead sessions
        """
        for session in [x for x in self.sessions.values() if x.is_dead()]:
            session.destroy()
            del self.sessions[session.key]

    def destroy(self):
        for session in self.sessions.values():
            session.deactivate()
        self.vacuum()

    def open_session(self, env, **kwargs):
        """
        Creates a new session for the :class:`aj.http.HttpContext`
        """
        client_info = {
            'address': env.get('REMOTE_ADDR', None),
        }
        session_key = self.generate_session_key(env)
        session = Session(session_key, client_info=client_info, **kwargs)
        self.sessions[session_key] = session
        return session

    def obtain_session(self, env):
        cookie_str = env.get('HTTP_COOKIE', None)
        session = None
        if cookie_str:
            cookie = Cookies.from_request(
                cookie_str,
                ignore_bad_cookies=True,
            ).get('session', None)
            if cookie and cookie.value:
                if cookie.value in self.sessions:
                    # Session found
                    session = self.sessions[cookie.value]
                    if session.is_dead():
                        session = None
        return session

    def handle(self, http_context):
        start_time = time.time()

        self.vacuum()

        session = self.obtain_session(http_context.env)
        gate = None

        if not session and aj.dev_autologin:
            username = pwd.getpwuid(os.geteuid()).pw_name
            logging.warn('Opening an autologin session for user %s', username)
            session = self.open_session(
                http_context.env,
                initial_identity=username
            )
            session.set_cookie(http_context)

        if session:
            session.touch()
            gate = session.gate
        else:
            gate = self.restricted_gate

        if http_context.path.startswith('/socket'):
            http_context.fallthrough(SocketIORouteHandler.get(self.context))
            http_context.respond_ok()
            return 'Socket closed'

        request_object = {
            'type': 'http',
            'context': http_context.serialize(),
        }

        # await response

        try:
            timeout = 60
            with Timeout(timeout) as t:
                q = gate.q_http_replies.register()
                rq = gate.stream.send(request_object)
                while True:
                    resp = q.get(t)
                    if resp.id == rq.id:
                        break
        # pylint: disable=E0712
        except Timeout:
            http_context.respond('504 Gateway Timeout')
            return 'Worker timeout'

        # ---

        if 'error' in resp.object:
            raise WorkerError(resp.object)

        for header in resp.object['headers']:
            http_context.add_header(*header)
            if header[0] == 'X-Session-Redirect':
                # new authenticated session
                username = header[1]
                logging.info('Opening a session for user %s', username)
                session = self.open_session(
                    http_context.env,
                    initial_identity=username
                )
                session.set_cookie(http_context)

        http_context.respond(resp.object['status'])
        content = resp.object['content']

        end_time = time.time()
        logging.debug(
            '%.03fs %12s   %s %s %s',
            end_time - start_time,
            str_fsize(len(content[0] if content else [])),
            str(http_context.status).split()[0],
            http_context.env['REQUEST_METHOD'],
            http_context.path
        )
        return content
Exemple #11
0
class Session(object):
    """
    Holds the HTTP session data
    """

    last_id = 0

    def __init__(self,
                 key,
                 gateway_middleware=None,
                 client_info=None,
                 auth_info=None,
                 session_max_time=3600,
                 **kwargs):
        Session.last_id += 1
        self.id = Session.last_id
        self.key = key
        self.client_info = client_info or {}
        self.data = {}
        self.identity = kwargs[
            'initial_identity'] if 'initial_identity' in kwargs.keys(
            ) else None
        self.auth_info = auth_info
        self.touch()
        self.active = True
        logging.info(
            'Opening a new worker gate for session %s, client %s',
            self.id,
            self.client_info['address'],
        )
        self.gate = WorkerGate(self,
                               gateway_middleware=gateway_middleware,
                               name='session %i' % self.id,
                               log_tag='worker',
                               **kwargs)
        self.session_max_time = session_max_time
        self.gate.start()
        logging.debug('New session %s', self.id)

    def destroy(self):
        logging.debug('Destroying session %s', self.id)
        self.gate.stop()

    def deactivate(self):
        """
        Marks this session as dead
        """
        self.active = False

    def touch(self):
        """
        Updates the "last used" timestamp
        """
        self.timestamp = time.time()

    def get_age(self):
        return time.time() - self.timestamp

    def is_dead(self):
        return not self.active or self.get_age() > self.session_max_time

    def set_cookie(self, http_context):
        """
        Adds headers to :class:`aj.http.HttpContext` that set
        the session cookie
        """
        cookie = Cookie('session', self.key, path='/',
                        httponly=True).render_response()
        http_context.add_header('Set-Cookie', cookie)

    def serialize(self):
        return {
            'key': self.key,
            'identity': self.identity,
            'timestamp': self.timestamp,
            'client_info': self.client_info
        }