def test_secure_dumps_and_loads(self):
        """ Tests secure_dumps and secure_loads"""
        testobj = {'a': 1, 'b': 2}
        testkey = 'mysecret'
        secured = secure_dumps(testobj, testkey)
        original = secure_loads(secured, testkey)
        self.assertEqual(testobj, original)
        self.assertTrue(isinstance(secured, basestring))
        self.assertTrue(':' in secured)

        large_testobj = [x for x in range(1000)]
        secured_comp = secure_dumps(large_testobj,
                                    testkey,
                                    compression_level=9)
        original_comp = secure_loads(secured_comp,
                                     testkey,
                                     compression_level=9)
        self.assertEqual(large_testobj, original_comp)
        secured = secure_dumps(large_testobj, testkey)
        self.assertTrue(len(secured_comp) < len(secured))

        testhash = 'myhash'
        secured = secure_dumps(testobj, testkey, testhash)
        original = secure_loads(secured, testkey, testhash)
        self.assertEqual(testobj, original)

        wrong1 = secure_loads(secured, testkey, 'wronghash')
        self.assertEqual(wrong1, None)
        wrong2 = secure_loads(secured, 'wrongkey', testhash)
        self.assertEqual(wrong2, None)
        wrong3 = secure_loads(secured, 'wrongkey', 'wronghash')
        self.assertEqual(wrong3, None)
        wrong4 = secure_loads('abc', 'a', 'b')
        self.assertEqual(wrong4, None)
Esempio n. 2
0
    def test_secure_dumps_and_loads(self):
        """ Tests secure_dumps and secure_loads"""
        testobj = {"a": 1, "b": 2}
        testkey = "mysecret"
        secured = secure_dumps(testobj, testkey)
        original = secure_loads(secured, testkey)
        self.assertEqual(testobj, original)
        self.assertTrue(isinstance(secured, basestring))
        self.assertTrue(":" in secured)

        large_testobj = [x for x in range(1000)]
        secured_comp = secure_dumps(large_testobj, testkey, compression_level=9)
        original_comp = secure_loads(secured_comp, testkey, compression_level=9)
        self.assertEqual(large_testobj, original_comp)
        secured = secure_dumps(large_testobj, testkey)
        self.assertTrue(len(secured_comp) < len(secured))

        testhash = "myhash"
        secured = secure_dumps(testobj, testkey, testhash)
        original = secure_loads(secured, testkey, testhash)
        self.assertEqual(testobj, original)

        wrong1 = secure_loads(secured, testkey, "wronghash")
        self.assertEqual(wrong1, None)
        wrong2 = secure_loads(secured, "wrongkey", testhash)
        self.assertEqual(wrong2, None)
        wrong3 = secure_loads(secured, "wrongkey", "wronghash")
        self.assertEqual(wrong3, None)
        wrong4 = secure_loads("abc", "a", "b")
        self.assertEqual(wrong4, None)
Esempio n. 3
0
    def test_secure_dumps_and_loads(self):
        """ Tests secure_dumps and secure_loads"""
        testobj = {'a': 1, 'b': 2}
        testkey = 'mysecret'
        secured = secure_dumps(testobj, testkey)
        original = secure_loads(secured, testkey)
        self.assertEqual(testobj, original)
        self.assertTrue(isinstance(secured, basestring))
        self.assertTrue(':' in secured)

        large_testobj = [x for x in range(1000)]
        secured_comp = secure_dumps(large_testobj, testkey, compression_level=9)
        original_comp = secure_loads(secured_comp, testkey, compression_level=9)
        self.assertEqual(large_testobj, original_comp)
        secured = secure_dumps(large_testobj, testkey)
        self.assertTrue(len(secured_comp) < len(secured))

        testhash = 'myhash'
        secured = secure_dumps(testobj, testkey, testhash)
        original = secure_loads(secured, testkey, testhash)
        self.assertEqual(testobj, original)

        wrong1 = secure_loads(secured, testkey, 'wronghash')
        self.assertEqual(wrong1, None)
        wrong2 = secure_loads(secured, 'wrongkey', testhash)
        self.assertEqual(wrong2, None)
        wrong3 = secure_loads(secured, 'wrongkey', 'wronghash')
        self.assertEqual(wrong3, None)
        wrong4 = secure_loads('abc', 'a', 'b')
        self.assertEqual(wrong4, None)
Esempio n. 4
0
    def connect(
        self,
        request=None,
        response=None,
        db=None,
        tablename='web2py_session',
        masterapp=None,
        migrate=True,
        separate=None,
        check_client=False,
        cookie_key=None,
        cookie_expires=None,
        compression_level=None
    ):
        """
        separate can be separate=lambda(session_name): session_name[-2:]
        and it is used to determine a session prefix.
        separate can be True and it is set to session_name[-2:]
        """
        if request is None:
            request = current.request
        if response is None:
            response = current.response
        if separate == True:
            separate = lambda session_name: session_name[-2:]
        self._unlock(response)
        if not masterapp:
            masterapp = request.application
        response.session_id_name = 'session_id_%s' % masterapp.lower()
        response.session_data_name = 'session_data_%s' % masterapp.lower()
        response.session_cookie_expires = cookie_expires

        # Load session data from cookie
        cookies = request.cookies

        # check if there is a session_id in cookies
        if response.session_id_name in cookies:
            response.session_id = \
                cookies[response.session_id_name].value
        else:
            response.session_id = None

        # check if there is session data in cookies
        if response.session_data_name in cookies:
            session_cookie_data = cookies[response.session_data_name].value
        else:
            session_cookie_data = None

        # if we are supposed to use cookie based session data
        if cookie_key:
            response.session_storage_type = 'cookie'
            response.session_cookie_key = cookie_key
            response.session_cookie_compression_level = compression_level
            if session_cookie_data:
                data = secure_loads(session_cookie_data, cookie_key,
                                    compression_level=compression_level)
                if data:
                    self.update(data)
        # else if we are supposed to use file based sessions
        elif not db:
            response.session_storage_type = 'file'
            if global_settings.db_sessions is True \
                    or masterapp in global_settings.db_sessions:
                return
            response.session_new = False
            client = request.client and request.client.replace(':', '.')
            if response.session_id:
                if regex_session_id.match(response.session_id):
                    response.session_filename = \
                        os.path.join(up(request.folder), masterapp,
                                     'sessions', response.session_id)
                else:
                    response.session_id = None
            # do not try load the data from file is these was data in cookie
            if response.session_id and not session_cookie_data:
                try:
                    response.session_file = \
                        open(response.session_filename, 'rb+')
                    try:
                        portalocker.lock(response.session_file,
                                         portalocker.LOCK_EX)
                        response.session_locked = True
                        self.update(cPickle.load(response.session_file))
                        response.session_file.seek(0)
                        oc = response.session_filename.split('/')[-1]\
                            .split('-')[0]
                        if check_client and client != oc:
                            raise Exception("cookie attack")
                    finally:
                        pass
                        #This causes admin login to break. Must find out why.
                        #self._close(response)
                except:
                    response.session_id = None
            if not response.session_id:
                uuid = web2py_uuid()
                response.session_id = '%s-%s' % (client, uuid)
                if separate:
                    prefix = separate(response.session_id)
                    response.session_id = '%s/%s' % \
                        (prefix, response.session_id)
                response.session_filename = \
                    os.path.join(up(request.folder), masterapp,
                                 'sessions', response.session_id)
                response.session_new = True
        # else the session goes in db
        else:
            response.session_storage_type = 'db'
            if global_settings.db_sessions is not True:
                global_settings.db_sessions.add(masterapp)
            if response.session_file:
                self._close(response)
            if settings.global_settings.web2py_runtime_gae:
                # in principle this could work without GAE
                request.tickets_db = db
            if masterapp == request.application:
                table_migrate = migrate
            else:
                table_migrate = False
            tname = tablename + '_' + masterapp
            table = db.get(tname, None)
            Field = db.Field
            if table is None:
                db.define_table(
                    tname,
                    Field('locked', 'boolean', default=False),
                    Field('client_ip', length=64),
                    Field('created_datetime', 'datetime',
                          default=request.now),
                    Field('modified_datetime', 'datetime'),
                    Field('unique_key', length=64),
                    Field('session_data', 'blob'),
                    migrate=table_migrate,
                )
                table = db[tname]  # to allow for lazy table
            try:

                # Get session data out of the database
                (record_id, unique_key) = response.session_id.split(':')
                if record_id == '0':
                    raise Exception('record_id == 0')
                        # Select from database
                if not session_cookie_data:
                    rows = db(table.id == record_id).select()
                    # Make sure the session data exists in the database
                    if len(rows) == 0 or rows[0].unique_key != unique_key:
                        raise Exception('No record')
                    # rows[0].update_record(locked=True)
                    # Unpickle the data
                    session_data = cPickle.loads(rows[0].session_data)
                    self.update(session_data)
            except Exception:
                record_id = None
                unique_key = web2py_uuid()
                session_data = {}
            response.session_id = '%s:%s' % (record_id, unique_key)
            response.session_db_table = table
            response.session_db_record_id = record_id
            response.session_db_unique_key = unique_key
        rcookies = response.cookies
        rcookies[response.session_id_name] = response.session_id
        rcookies[response.session_id_name]['path'] = '/'
        if cookie_expires:
            rcookies[response.session_id_name][
                'expires'] = cookie_expires.strftime(FMT)
        # if not cookie_key, but session_data_name in cookies
        # expire session_data_name from cookies
        if session_cookie_data:
            rcookies[response.session_data_name] = 'expired'
            rcookies[response.session_data_name]['path'] = '/'
            rcookies[response.session_data_name]['expires'] = PAST
        if self.flash:
            (response.flash, self.flash) = (self.flash, None)
Esempio n. 5
0
    def connect(self,
                request=None,
                response=None,
                db=None,
                tablename='web2py_session',
                masterapp=None,
                migrate=True,
                separate=None,
                check_client=False,
                cookie_key=None,
                cookie_expires=None,
                compression_level=None):
        """
        separate can be separate=lambda(session_name): session_name[-2:]
        and it is used to determine a session prefix.
        separate can be True and it is set to session_name[-2:]
        """
        request = request or current.request
        response = response or current.response
        masterapp = masterapp or request.application
        cookies = request.cookies

        self._unlock(response)

        response.session_masterapp = masterapp
        response.session_id_name = 'session_id_%s' % masterapp.lower()
        response.session_data_name = 'session_data_%s' % masterapp.lower()
        response.session_cookie_expires = cookie_expires
        response.session_client = str(request.client).replace(':', '.')
        response.session_cookie_key = cookie_key
        response.session_cookie_compression_level = compression_level

        # check if there is a session_id in cookies
        try:
            response.session_id = cookies[response.session_id_name].value
        except KeyError:
            response.session_id = None

        # if we are supposed to use cookie based session data
        if cookie_key:
            response.session_storage_type = 'cookie'
        elif db:
            response.session_storage_type = 'db'
        else:
            response.session_storage_type = 'file'
            # why do we do this?
            # because connect may be called twice, by web2py and in models.
            # the first time there is no db yet so it should do nothing
            if (global_settings.db_sessions is True
                    or masterapp in global_settings.db_sessions):
                return

        if response.session_storage_type == 'cookie':
            # check if there is session data in cookies
            if response.session_data_name in cookies:
                session_cookie_data = cookies[response.session_data_name].value
            else:
                session_cookie_data = None
            if session_cookie_data:
                data = secure_loads(session_cookie_data,
                                    cookie_key,
                                    compression_level=compression_level)
                if data:
                    self.update(data)
            response.session_id = True

        # else if we are supposed to use file based sessions
        elif response.session_storage_type == 'file':
            response.session_new = False
            response.session_file = None
            # check if the session_id points to a valid sesion filename
            if response.session_id:
                if not regex_session_id.match(response.session_id):
                    response.session_id = None
                else:
                    response.session_filename = \
                        os.path.join(up(request.folder), masterapp,
                                     'sessions', response.session_id)
                    try:
                        response.session_file = \
                            open(response.session_filename, 'rb+')
                        portalocker.lock(response.session_file,
                                         portalocker.LOCK_EX)
                        response.session_locked = True
                        self.update(cPickle.load(response.session_file))
                        response.session_file.seek(0)
                        oc = response.session_filename.split('/')[-1].split(
                            '-')[0]
                        if check_client and response.session_client != oc:
                            raise Exception("cookie attack")
                    except:
                        response.session_id = None
            if not response.session_id:
                uuid = web2py_uuid()
                response.session_id = '%s-%s' % (response.session_client, uuid)
                separate = separate and (
                    lambda session_name: session_name[-2:])
                if separate:
                    prefix = separate(response.session_id)
                    response.session_id = '%s/%s' % (prefix,
                                                     response.session_id)
                response.session_filename = \
                    os.path.join(up(request.folder), masterapp,
                                 'sessions', response.session_id)
                response.session_new = True

        # else the session goes in db
        elif response.session_storage_type == 'db':
            if global_settings.db_sessions is not True:
                global_settings.db_sessions.add(masterapp)
            # if had a session on file alreday, close it (yes, can happen)
            if response.session_file:
                self._close(response)
            # if on GAE tickets go also in DB
            if settings.global_settings.web2py_runtime_gae:
                request.tickets_db = db
            table_migrate = (masterapp == request.application)
            tname = tablename + '_' + masterapp
            table = db.get(tname, None)
            Field = db.Field
            if table is None:
                db.define_table(
                    tname,
                    Field('locked', 'boolean', default=False),
                    Field('client_ip', length=64),
                    Field('created_datetime', 'datetime', default=request.now),
                    Field('modified_datetime', 'datetime'),
                    Field('unique_key', length=64),
                    Field('session_data', 'blob'),
                    migrate=table_migrate,
                )
                table = db[tname]  # to allow for lazy table
            response.session_db_table = table
            if response.session_id:
                # Get session data out of the database
                try:
                    (record_id, unique_key) = response.session_id.split(':')
                    record_id = long(record_id)
                except (TypeError, ValueError):
                    record_id = None

                # Select from database
                if record_id:
                    row = table(record_id)  #,unique_key=unique_key)
                    # Make sure the session data exists in the database
                    if row:
                        # rows[0].update_record(locked=True)
                        # Unpickle the data
                        session_data = cPickle.loads(row.session_data)
                        self.update(session_data)
                    else:
                        record_id = None
                if record_id:
                    response.session_id = '%s:%s' % (record_id, unique_key)
                    response.session_db_unique_key = unique_key
                    response.session_db_record_id = record_id
                else:
                    response.session_id = None
                    response.session_new = True

        if self.flash:
            (response.flash, self.flash) = (self.flash, None)

        session_pickled = cPickle.dumps(self)
        response.session_hash = hashlib.md5(session_pickled).hexdigest()
Esempio n. 6
0
    def connect(self,
                request=None,
                response=None,
                db=None,
                tablename='web2py_session',
                masterapp=None,
                migrate=True,
                separate=None,
                check_client=False,
                cookie_key=None,
                cookie_expires=None,
                compression_level=None):
        """
        separate can be separate=lambda(session_name): session_name[-2:]
        and it is used to determine a session prefix.
        separate can be True and it is set to session_name[-2:]
        """
        if request is None:
            request = current.request
        if response is None:
            response = current.response
        if separate is True:
            separate = lambda session_name: session_name[-2:]
        self._unlock(response)
        if not masterapp:
            masterapp = request.application
        response.session_id_name = 'session_id_%s' % masterapp.lower()
        response.session_data_name = 'session_data_%s' % masterapp.lower()
        response.session_cookie_expires = cookie_expires

        # Load session data from cookie
        cookies = request.cookies

        # check if there is a session_id in cookies
        if response.session_id_name in cookies:
            response.session_id = \
                cookies[response.session_id_name].value
        else:
            response.session_id = None

        # check if there is session data in cookies
        if response.session_data_name in cookies:
            session_cookie_data = cookies[response.session_data_name].value
        else:
            session_cookie_data = None

        # if we are supposed to use cookie based session data
        if cookie_key:
            response.session_storage_type = 'cookie'
            response.session_cookie_key = cookie_key
            response.session_cookie_compression_level = compression_level
            if session_cookie_data:
                data = secure_loads(session_cookie_data,
                                    cookie_key,
                                    compression_level=compression_level)
                if data:
                    self.update(data)
        # else if we are supposed to use file based sessions
        elif not db:
            response.session_storage_type = 'file'
            if global_settings.db_sessions is True \
                    or masterapp in global_settings.db_sessions:
                return
            response.session_new = False
            client = request.client and request.client.replace(':', '.')
            if response.session_id:
                if regex_session_id.match(response.session_id):
                    response.session_filename = \
                        os.path.join(up(request.folder), masterapp,
                                     'sessions', response.session_id)
                else:
                    response.session_id = None
            # do not try load the data from file is these was data in cookie
            if response.session_id and not session_cookie_data:
                # os.path.exists(response.session_filename):
                try:
                    response.session_file = \
                        open(response.session_filename, 'rb+')
                    try:
                        portalocker.lock(response.session_file,
                                         portalocker.LOCK_EX)
                        response.session_locked = True
                        self.update(cPickle.load(response.session_file))
                        response.session_file.seek(0)
                        oc = response.session_filename.split('/')[-1]\
                            .split('-')[0]
                        if check_client and client != oc:
                            raise Exception("cookie attack")
                    except:
                        response.session_id = None
                    finally:
                        pass
                        #This causes admin login to break. Must find out why.
                        #self._close(response)
                except:
                    response.session_file = None
            if not response.session_id:
                uuid = web2py_uuid()
                response.session_id = '%s-%s' % (client, uuid)
                if separate:
                    prefix = separate(response.session_id)
                    response.session_id = '%s/%s' % \
                        (prefix, response.session_id)
                response.session_filename = \
                    os.path.join(up(request.folder), masterapp,
                                 'sessions', response.session_id)
                response.session_new = True
        # else the session goes in db
        else:
            response.session_storage_type = 'db'
            if global_settings.db_sessions is not True:
                global_settings.db_sessions.add(masterapp)
            if response.session_file:
                self._close(response)
            if settings.global_settings.web2py_runtime_gae:
                # in principle this could work without GAE
                request.tickets_db = db
            if masterapp == request.application:
                table_migrate = migrate
            else:
                table_migrate = False
            tname = tablename + '_' + masterapp
            table = db.get(tname, None)
            Field = db.Field
            if table is None:
                db.define_table(
                    tname,
                    Field('locked', 'boolean', default=False),
                    Field('client_ip', length=64),
                    Field('created_datetime', 'datetime', default=request.now),
                    Field('modified_datetime', 'datetime'),
                    Field('unique_key', length=64),
                    Field('session_data', 'blob'),
                    migrate=table_migrate,
                )
                table = db[tname]  # to allow for lazy table
            try:

                # Get session data out of the database
                (record_id, unique_key) = response.session_id.split(':')
                if record_id == '0':
                    raise Exception('record_id == 0')
                    # Select from database
                if not session_cookie_data:
                    rows = db(table.id == record_id).select()
                    # Make sure the session data exists in the database
                    if len(rows) == 0 or rows[0].unique_key != unique_key:
                        raise Exception('No record')
                    # rows[0].update_record(locked=True)
                    # Unpickle the data
                    session_data = cPickle.loads(rows[0].session_data)
                    self.update(session_data)
            except Exception:
                record_id = None
                unique_key = web2py_uuid()
                session_data = {}
            response.session_id = '%s:%s' % (record_id, unique_key)
            response.session_db_table = table
            response.session_db_record_id = record_id
            response.session_db_unique_key = unique_key
            # keep tablename parameter for use in session renew
            response.session_table_name = tablename
        rcookies = response.cookies
        rcookies[response.session_id_name] = response.session_id
        rcookies[response.session_id_name]['path'] = '/'
        if cookie_expires:
            rcookies[response.
                     session_id_name]['expires'] = cookie_expires.strftime(FMT)
        # if not cookie_key, but session_data_name in cookies
        # expire session_data_name from cookies
        if session_cookie_data:
            rcookies[response.session_data_name] = 'expired'
            rcookies[response.session_data_name]['path'] = '/'
            rcookies[response.session_data_name]['expires'] = PAST
        if self.flash:
            (response.flash, self.flash) = (self.flash, None)
Esempio n. 7
0
    def connect(
        self,
        request=None,
        response=None,
        db=None,
        tablename='web2py_session',
        masterapp=None,
        migrate=True,
        separate=None,
        check_client=False,
        cookie_key=None,
        cookie_expires=None,
        compression_level=None
    ):
        """
        separate can be separate=lambda(session_name): session_name[-2:]
        and it is used to determine a session prefix.
        separate can be True and it is set to session_name[-2:]
        """
        request = request or current.request
        response = response or current.response
        masterapp = masterapp or request.application
        cookies = request.cookies

        self._unlock(response)

        response.session_masterapp = masterapp
        response.session_id_name = 'session_id_%s' % masterapp.lower()
        response.session_data_name = 'session_data_%s' % masterapp.lower()
        response.session_cookie_expires = cookie_expires
        response.session_client = str(request.client).replace(':', '.')
        response.session_cookie_key = cookie_key
        response.session_cookie_compression_level = compression_level

        # check if there is a session_id in cookies
        try:
            response.session_id = cookies[response.session_id_name].value
        except KeyError:
            response.session_id = None

        # if we are supposed to use cookie based session data
        if cookie_key:
            response.session_storage_type = 'cookie'
        elif db:
            response.session_storage_type = 'db'
        else:
            response.session_storage_type = 'file'
            # why do we do this?
            # because connect may be called twice, by web2py and in models.
            # the first time there is no db yet so it should do nothing
            if (global_settings.db_sessions is True or
                masterapp in global_settings.db_sessions):
                return

        if response.session_storage_type == 'cookie':
            # check if there is session data in cookies
            if response.session_data_name in cookies:
                session_cookie_data = cookies[response.session_data_name].value
            else:
                session_cookie_data = None
            if session_cookie_data:
                data = secure_loads(session_cookie_data, cookie_key,
                                    compression_level=compression_level)
                if data:
                    self.update(data)
            response.session_id = True

        # else if we are supposed to use file based sessions
        elif response.session_storage_type == 'file':
            response.session_new = False
            response.session_file = None
            # check if the session_id points to a valid sesion filename
            if response.session_id:
                if not regex_session_id.match(response.session_id):
                    response.session_id = None
                else:
                    response.session_filename = \
                        os.path.join(up(request.folder), masterapp,
                                     'sessions', response.session_id)
                    try:
                        response.session_file = \
                            open(response.session_filename, 'rb+')
                        portalocker.lock(response.session_file,
                                         portalocker.LOCK_EX)
                        response.session_locked = True
                        self.update(cPickle.load(response.session_file))
                        response.session_file.seek(0)
                        oc = response.session_filename.split('/')[-1].split('-')[0]
                        if check_client and response.session_client != oc:
                            raise Exception("cookie attack")
                    except:
                        response.session_id = None
            if not response.session_id:
                uuid = web2py_uuid()
                response.session_id = '%s-%s' % (response.session_client, uuid)
                separate = separate and (lambda session_name: session_name[-2:])
                if separate:
                    prefix = separate(response.session_id)
                    response.session_id = '%s/%s' % (prefix, response.session_id)
                response.session_filename = \
                    os.path.join(up(request.folder), masterapp,
                                 'sessions', response.session_id)
                response.session_new = True

        # else the session goes in db
        elif response.session_storage_type == 'db':
            if global_settings.db_sessions is not True:
                global_settings.db_sessions.add(masterapp)
            # if had a session on file alreday, close it (yes, can happen)
            if response.session_file:
                self._close(response)
            # if on GAE tickets go also in DB
            if settings.global_settings.web2py_runtime_gae:
                request.tickets_db = db
            table_migrate = (masterapp == request.application)
            tname = tablename + '_' + masterapp
            table = db.get(tname, None)
            Field = db.Field
            if table is None:
                db.define_table(
                    tname,
                    Field('locked', 'boolean', default=False),
                    Field('client_ip', length=64),
                    Field('created_datetime', 'datetime',
                          default=request.now),
                    Field('modified_datetime', 'datetime'),
                    Field('unique_key', length=64),
                    Field('session_data', 'blob'),
                    migrate=table_migrate,
                )
                table = db[tname]  # to allow for lazy table
            response.session_db_table = table
            if response.session_id:
                # Get session data out of the database
                try:
                    (record_id, unique_key) = response.session_id.split(':')
                    record_id = long(record_id)
                except (TypeError,ValueError):
                    record_id = None

                # Select from database
                if record_id:
                    row = table(record_id) #,unique_key=unique_key)
                    # Make sure the session data exists in the database
                    if row:
                        # rows[0].update_record(locked=True)
                        # Unpickle the data
                        session_data = cPickle.loads(row.session_data)
                        self.update(session_data)
                    else:
                        record_id = None
                if record_id:
                    response.session_id = '%s:%s' % (record_id, unique_key)
                    response.session_db_unique_key = unique_key
                    response.session_db_record_id = record_id
                else:
                    response.session_id = None
                    response.session_new = True

        if self.flash:
            (response.flash, self.flash) = (self.flash, None)
Esempio n. 8
0
    def connect(
        self,
        request=None,
        response=None,
        db=None,
        tablename="web2py_session",
        masterapp=None,
        migrate=True,
        separate=None,
        check_client=False,
        cookie_key=None,
        cookie_expires=None,
        compression_level=None,
    ):
        """
        separate can be separate=lambda(session_name): session_name[-2:]
        and it is used to determine a session prefix.
        separate can be True and it is set to session_name[-2:]
        """
        if request is None:
            request = current.request
        if response is None:
            response = current.response
        if separate is True:
            separate = lambda session_name: session_name[-2:]
        self._unlock(response)
        if not masterapp:
            masterapp = request.application
        response.session_id_name = "session_id_%s" % masterapp.lower()
        response.session_data_name = "session_data_%s" % masterapp.lower()
        response.session_cookie_expires = cookie_expires

        # Load session data from cookie
        cookies = request.cookies

        # check if there is a session_id in cookies
        if response.session_id_name in cookies:
            response.session_id = cookies[response.session_id_name].value
        else:
            response.session_id = None

        # check if there is session data in cookies
        if response.session_data_name in cookies:
            session_cookie_data = cookies[response.session_data_name].value
        else:
            session_cookie_data = None

        # if we are supposed to use cookie based session data
        if cookie_key:
            response.session_storage_type = "cookie"
            response.session_cookie_key = cookie_key
            response.session_cookie_compression_level = compression_level
            if session_cookie_data:
                data = secure_loads(session_cookie_data, cookie_key, compression_level=compression_level)
                if data:
                    self.update(data)
        # else if we are supposed to use file based sessions
        elif not db:
            response.session_storage_type = "file"
            if global_settings.db_sessions is True or masterapp in global_settings.db_sessions:
                return
            response.session_new = False
            client = request.client and request.client.replace(":", ".")
            if response.session_id:
                if regex_session_id.match(response.session_id):
                    response.session_filename = os.path.join(
                        up(request.folder), masterapp, "sessions", response.session_id
                    )
                else:
                    response.session_id = None
            # do not try load the data from file is these was data in cookie
            if response.session_id and not session_cookie_data:
                # os.path.exists(response.session_filename):
                try:
                    response.session_file = open(response.session_filename, "rb+")
                    try:
                        portalocker.lock(response.session_file, portalocker.LOCK_EX)
                        response.session_locked = True
                        self.update(cPickle.load(response.session_file))
                        response.session_file.seek(0)
                        oc = response.session_filename.split("/")[-1].split("-")[0]
                        if check_client and client != oc:
                            raise Exception("cookie attack")
                    except:
                        response.session_id = None
                    finally:
                        pass
                        # This causes admin login to break. Must find out why.
                        # self._close(response)
                except:
                    response.session_file = None
            if not response.session_id:
                uuid = web2py_uuid()
                response.session_id = "%s-%s" % (client, uuid)
                if separate:
                    prefix = separate(response.session_id)
                    response.session_id = "%s/%s" % (prefix, response.session_id)
                response.session_filename = os.path.join(up(request.folder), masterapp, "sessions", response.session_id)
                response.session_new = True
        # else the session goes in db
        else:
            response.session_storage_type = "db"
            if global_settings.db_sessions is not True:
                global_settings.db_sessions.add(masterapp)
            if response.session_file:
                self._close(response)
            if settings.global_settings.web2py_runtime_gae:
                # in principle this could work without GAE
                request.tickets_db = db
            if masterapp == request.application:
                table_migrate = migrate
            else:
                table_migrate = False
            tname = tablename + "_" + masterapp
            table = db.get(tname, None)
            Field = db.Field
            if table is None:
                db.define_table(
                    tname,
                    Field("locked", "boolean", default=False),
                    Field("client_ip", length=64),
                    Field("created_datetime", "datetime", default=request.now),
                    Field("modified_datetime", "datetime"),
                    Field("unique_key", length=64),
                    Field("session_data", "blob"),
                    migrate=table_migrate,
                )
                table = db[tname]  # to allow for lazy table
            try:

                # Get session data out of the database
                (record_id, unique_key) = response.session_id.split(":")
                if record_id == "0":
                    raise Exception("record_id == 0")
                    # Select from database
                if not session_cookie_data:
                    rows = db(table.id == record_id).select()
                    # Make sure the session data exists in the database
                    if len(rows) == 0 or rows[0].unique_key != unique_key:
                        raise Exception("No record")
                    # rows[0].update_record(locked=True)
                    # Unpickle the data
                    session_data = cPickle.loads(rows[0].session_data)
                    self.update(session_data)
            except Exception:
                record_id = None
                unique_key = web2py_uuid()
                session_data = {}
            response.session_id = "%s:%s" % (record_id, unique_key)
            response.session_db_table = table
            response.session_db_record_id = record_id
            response.session_db_unique_key = unique_key
            # keep tablename parameter for use in session renew
            response.session_table_name = tablename
        rcookies = response.cookies
        rcookies[response.session_id_name] = response.session_id
        rcookies[response.session_id_name]["path"] = "/"
        if cookie_expires:
            rcookies[response.session_id_name]["expires"] = cookie_expires.strftime(FMT)
        # if not cookie_key, but session_data_name in cookies
        # expire session_data_name from cookies
        if session_cookie_data:
            rcookies[response.session_data_name] = "expired"
            rcookies[response.session_data_name]["path"] = "/"
            rcookies[response.session_data_name]["expires"] = PAST
        if self.flash:
            (response.flash, self.flash) = (self.flash, None)