Giter Club home page Giter Club logo

flask-session's Issues

Handling exceptions

Hi!

How could one handle exceptions with flask-session? When using SESSION_TYPE='redis' and redis is not available for some reason I can't find a way to catch the redis.exceptions.ConnectionError exception.

Any ideas how to do this?

Thanks for this awesome extension!

Duplicate session ID in SQLAlchemy driver in ClosingIterator

We have some extra logging code that makes use of the session in a ClosingIterator:

    def setup_logging_middleware(self):
        """Add local variables we will use per request.

        Right now we hang logging off of it.
        """
        from werkzeug.wsgi import ClosingIterator
        from werkzeug.local import release_local

        def my_release_locals():
            release_local(log_threadLocal)

        def my_make_middleware(app):
            """Wrap a WSGI application so that cleaning up happens after request end."""
            def application(environ, start_response):
                return ClosingIterator(app(environ, start_response), my_release_locals)

            return application
        self.wsgi_app = my_make_middleware(self.wsgi_app)

Every once in a great while we see the following error pop up:

2017-04-27T11:33:37.187730+00:00 app[web.1]: Traceback (most recent call last):
2017-04-27T11:33:37.187732+00:00 app[web.1]:   File "/app/.heroku/python/lib/python3.6/site-packages/sqlalchemy/engine/base.py", line 1182, in _execute_context
2017-04-27T11:33:37.187733+00:00 app[web.1]:     context)
2017-04-27T11:33:37.187734+00:00 app[web.1]:   File "/app/.heroku/python/lib/python3.6/site-packages/sqlalchemy/engine/default.py", line 470, in do_execute
2017-04-27T11:33:37.187735+00:00 app[web.1]:     cursor.execute(statement, parameters)
2017-04-27T11:33:37.187735+00:00 app[web.1]: psycopg2.IntegrityError: duplicate key value violates unique constraint "flask_session_session_id_key"
2017-04-27T11:33:37.187739+00:00 app[web.1]: DETAIL:  Key (session_id)=(session:redacted-8e4b-481a-8788-redacted) already exists.
2017-04-27T11:33:37.187740+00:00 app[web.1]: 
2017-04-27T11:33:37.187740+00:00 app[web.1]: 
2017-04-27T11:33:37.187741+00:00 app[web.1]: The above exception was the direct cause of the following exception:
2017-04-27T11:33:37.187742+00:00 app[web.1]: 
2017-04-27T11:33:37.187742+00:00 app[web.1]: Traceback (most recent call last):
2017-04-27T11:33:37.187743+00:00 app[web.1]:   File "/app/.heroku/python/lib/python3.6/site-packages/flask/app.py", line 1982, in wsgi_app
2017-04-27T11:33:37.187743+00:00 app[web.1]:     response = self.full_dispatch_request()
2017-04-27T11:33:37.187744+00:00 app[web.1]:   File "/app/.heroku/python/lib/python3.6/site-packages/flask/app.py", line 1615, in full_dispatch_request
2017-04-27T11:33:37.187745+00:00 app[web.1]:     return self.finalize_request(rv)
2017-04-27T11:33:37.187745+00:00 app[web.1]:   File "/app/.heroku/python/lib/python3.6/site-packages/flask/app.py", line 1632, in finalize_request
2017-04-27T11:33:37.187746+00:00 app[web.1]:     response = self.process_response(response)
2017-04-27T11:33:37.187747+00:00 app[web.1]:   File "/app/.heroku/python/lib/python3.6/site-packages/flask/app.py", line 1858, in process_response
2017-04-27T11:33:37.187748+00:00 app[web.1]:     self.save_session(ctx.session, response)
2017-04-27T11:33:37.187749+00:00 app[web.1]:   File "/app/.heroku/python/lib/python3.6/site-packages/flask/app.py", line 924, in save_session
2017-04-27T11:33:37.187749+00:00 app[web.1]:     return self.session_interface.save_session(self, session, response)
2017-04-27T11:33:37.187750+00:00 app[web.1]:   File "/app/.heroku/python/lib/python3.6/site-packages/flask_session/sessions.py", line 556, in save_session
2017-04-27T11:33:37.187751+00:00 app[web.1]:     self.db.session.commit()
2017-04-27T11:33:37.187752+00:00 app[web.1]:   File "/app/.heroku/python/lib/python3.6/site-packages/sqlalchemy/orm/scoping.py", line 157, in do
2017-04-27T11:33:37.187752+00:00 app[web.1]:     return getattr(self.registry(), name)(*args, **kwargs)
2017-04-27T11:33:37.187753+00:00 app[web.1]:   File "/app/.heroku/python/lib/python3.6/site-packages/sqlalchemy/orm/session.py", line 874, in commit
2017-04-27T11:33:37.187754+00:00 app[web.1]:     self.transaction.commit()
2017-04-27T11:33:37.187755+00:00 app[web.1]:   File "/app/.heroku/python/lib/python3.6/site-packages/sqlalchemy/orm/session.py", line 461, in commit
2017-04-27T11:33:37.187755+00:00 app[web.1]:     self._prepare_impl()
2017-04-27T11:33:37.187756+00:00 app[web.1]:   File "/app/.heroku/python/lib/python3.6/site-packages/sqlalchemy/orm/session.py", line 441, in _prepare_impl
2017-04-27T11:33:37.187757+00:00 app[web.1]:     self.session.flush()
2017-04-27T11:33:37.187757+00:00 app[web.1]:   File "/app/.heroku/python/lib/python3.6/site-packages/sqlalchemy/orm/session.py", line 2139, in flush
2017-04-27T11:33:37.187758+00:00 app[web.1]:     self._flush(objects)
2017-04-27T11:33:37.187758+00:00 app[web.1]:   File "/app/.heroku/python/lib/python3.6/site-packages/sqlalchemy/orm/session.py", line 2259, in _flush
2017-04-27T11:33:37.187759+00:00 app[web.1]:     transaction.rollback(_capture_exception=True)
2017-04-27T11:33:37.187760+00:00 app[web.1]:   File "/app/.heroku/python/lib/python3.6/site-packages/sqlalchemy/util/langhelpers.py", line 66, in __exit__
2017-04-27T11:33:37.187760+00:00 app[web.1]:     compat.reraise(exc_type, exc_value, exc_tb)
2017-04-27T11:33:37.187761+00:00 app[web.1]:   File "/app/.heroku/python/lib/python3.6/site-packages/sqlalchemy/util/compat.py", line 187, in reraise
2017-04-27T11:33:37.187761+00:00 app[web.1]:     raise value
2017-04-27T11:33:37.187762+00:00 app[web.1]:   File "/app/.heroku/python/lib/python3.6/site-packages/sqlalchemy/orm/session.py", line 2223, in _flush
2017-04-27T11:33:37.187763+00:00 app[web.1]:     flush_context.execute()
2017-04-27T11:33:37.187763+00:00 app[web.1]:   File "/app/.heroku/python/lib/python3.6/site-packages/sqlalchemy/orm/unitofwork.py", line 389, in execute
2017-04-27T11:33:37.187764+00:00 app[web.1]:     rec.execute(self)
2017-04-27T11:33:37.187765+00:00 app[web.1]:   File "/app/.heroku/python/lib/python3.6/site-packages/sqlalchemy/orm/unitofwork.py", line 548, in execute
2017-04-27T11:33:37.187765+00:00 app[web.1]:     uow
2017-04-27T11:33:37.187766+00:00 app[web.1]:   File "/app/.heroku/python/lib/python3.6/site-packages/sqlalchemy/orm/persistence.py", line 181, in save_obj
2017-04-27T11:33:37.187767+00:00 app[web.1]:     mapper, table, insert)
2017-04-27T11:33:37.187767+00:00 app[web.1]:   File "/app/.heroku/python/lib/python3.6/site-packages/sqlalchemy/orm/persistence.py", line 835, in _emit_insert_statements
2017-04-27T11:33:37.187768+00:00 app[web.1]:     execute(statement, params)
2017-04-27T11:33:37.187769+00:00 app[web.1]:   File "/app/.heroku/python/lib/python3.6/site-packages/sqlalchemy/engine/base.py", line 945, in execute
2017-04-27T11:33:37.187769+00:00 app[web.1]:     return meth(self, multiparams, params)
2017-04-27T11:33:37.187770+00:00 app[web.1]:   File "/app/.heroku/python/lib/python3.6/site-packages/sqlalchemy/sql/elements.py", line 263, in _execute_on_connection
2017-04-27T11:33:37.187770+00:00 app[web.1]:     return connection._execute_clauseelement(self, multiparams, params)
2017-04-27T11:33:37.187771+00:00 app[web.1]:   File "/app/.heroku/python/lib/python3.6/site-packages/sqlalchemy/engine/base.py", line 1053, in _execute_clauseelement
2017-04-27T11:33:37.187772+00:00 app[web.1]:     compiled_sql, distilled_params
2017-04-27T11:33:37.187772+00:00 app[web.1]:   File "/app/.heroku/python/lib/python3.6/site-packages/sqlalchemy/engine/base.py", line 1189, in _execute_context
2017-04-27T11:33:37.187773+00:00 app[web.1]:     context)
2017-04-27T11:33:37.187778+00:00 app[web.1]:   File "/app/.heroku/python/lib/python3.6/site-packages/sqlalchemy/engine/base.py", line 1402, in _handle_dbapi_exception
2017-04-27T11:33:37.187779+00:00 app[web.1]:     exc_info
2017-04-27T11:33:37.187780+00:00 app[web.1]:   File "/app/.heroku/python/lib/python3.6/site-packages/sqlalchemy/util/compat.py", line 203, in raise_from_cause
2017-04-27T11:33:37.187780+00:00 app[web.1]:     reraise(type(exception), exception, tb=exc_tb, cause=cause)
2017-04-27T11:33:37.187781+00:00 app[web.1]:   File "/app/.heroku/python/lib/python3.6/site-packages/sqlalchemy/util/compat.py", line 186, in reraise
2017-04-27T11:33:37.187781+00:00 app[web.1]:     raise value.with_traceback(tb)
2017-04-27T11:33:37.187782+00:00 app[web.1]:   File "/app/.heroku/python/lib/python3.6/site-packages/sqlalchemy/engine/base.py", line 1182, in _execute_context
2017-04-27T11:33:37.187783+00:00 app[web.1]:     context)
2017-04-27T11:33:37.187784+00:00 app[web.1]:   File "/app/.heroku/python/lib/python3.6/site-packages/sqlalchemy/engine/default.py", line 470, in do_execute
2017-04-27T11:33:37.187784+00:00 app[web.1]:     cursor.execute(statement, parameters)
2017-04-27T11:33:37.187786+00:00 app[web.1]: sqlalchemy.exc.IntegrityError: (psycopg2.IntegrityError) duplicate key value violates unique constraint "flask_session_session_id_key"
2017-04-27T11:33:37.187787+00:00 app[web.1]: DETAIL:  Key (session_id)=(session:redacted-8e4b-481a-8788-redacted) already exists.
2017-04-27T11:33:37.187789+00:00 app[web.1]:  [SQL: 'INSERT INTO flask_session (session_id, data, expiry) VALUES (%(session_id)s, %(data)s, %(expiry)s) RETURNING flask_session.id'] [parameters: {'session_id': 'session:redacted-8e4b-481a-8788-redacted', 'data': <psycopg2.extensions.Binary object at 0x7fb166e10120>, 'expiry': datetime.datetime(2017, 5, 28, 11, 33, 37, 174935)}]

Redis support

Hello,

Do you have any examples for redis support? It seems to be not working and base on the code it doesn't connect to the settings specified (url, key) etc..

An error occurred when create_app was executed twice

This is create_app function:

import flask
from flask.ext.session import Session
from .models import db

sess = Session()


def create_app():
    app = flask.Flask(__name__)

    app.config['SQLALCHEMY_DATABASE_URI'] = 'sqlite:///:memory:'
    app.config['SQLALCHEMY_ECHO'] = True

    app.config['SESSION_SQLALCHEMY'] = db
    app.config['SESSION_TYPE'] = 'sqlalchemy'
    sess.init_app(app)
    db.init_app(app)
    with app.app_context():
        db.create_all()

    return app

Then exec this code:

    app1 = create_app()
    app2 = create_app()

An error occurred:

Traceback (most recent call last):
  File "./runserver.py", line 12, in <module>
    main()
  File "./runserver.py", line 8, in main
    app2 = create_app()
  File "/home/computer/code/project/flownotebook/backend/flownotebook/__init__.py", line 18, in create_app
    sess.init_app(app)
  File "/usr/local/lib/python3.5/dist-packages/flask_session/__init__.py", line 61, in init_app
    app.session_interface = self._get_interface(app)
  File "/usr/local/lib/python3.5/dist-packages/flask_session/__init__.py", line 105, in _get_interface
    config['SESSION_PERMANENT'])
  File "/usr/local/lib/python3.5/dist-packages/flask_session/sessions.py", line 478, in __init__
    class Session(self.db.Model):
  File "/usr/local/lib/python3.5/dist-packages/flask_sqlalchemy/__init__.py", line 602, in __init__
    DeclarativeMeta.__init__(self, name, bases, d)
  File "/usr/local/lib/python3.5/dist-packages/sqlalchemy/ext/declarative/api.py", line 64, in __init__
    _as_declarative(cls, classname, cls.__dict__)
  File "/usr/local/lib/python3.5/dist-packages/sqlalchemy/ext/declarative/base.py", line 88, in _as_declarative
    _MapperConfig.setup_mapping(cls, classname, dict_)
  File "/usr/local/lib/python3.5/dist-packages/sqlalchemy/ext/declarative/base.py", line 103, in setup_mapping
    cfg_cls(cls_, classname, dict_)
  File "/usr/local/lib/python3.5/dist-packages/sqlalchemy/ext/declarative/base.py", line 131, in __init__
    self._setup_table()
  File "/usr/local/lib/python3.5/dist-packages/sqlalchemy/ext/declarative/base.py", line 395, in _setup_table
    **table_kw)
  File "/usr/local/lib/python3.5/dist-packages/sqlalchemy/sql/schema.py", line 421, in __new__
    "existing Table object." % key)
sqlalchemy.exc.InvalidRequestError: Table 'sessions' is already defined for this MetaData instance.  Specify 'extend_existing=True' to redefine options and columns on an existing Table object.

If I comment sess.init_app(app), this code works fine.

I guess that the two app instance shared the same database, repeat exec the function create_all(), my own definition of those tables can be created good, but the sessions table by using flask-session can not work in this situation.

Session fails because of no secret_key

When no secret key is set the get_signer returns None but this is not catched.

2017-02-16 19:17:08,522 domogik.admin.application ERROR Request finalizing failed with an error while handling an error Traceback (most recent call last): File "/usr/local/lib/python2.7/dist-packages/flask/app.py", line 1632, in finalize_request response = self.process_response(response) File "/usr/local/lib/python2.7/dist-packages/flask/app.py", line 1858, in process_response self.save_session(ctx.session, response) File "/usr/local/lib/python2.7/dist-packages/flask/app.py", line 924, in save_session return self.session_interface.save_session(self, session, response) File "/usr/local/lib/python2.7/dist-packages/Flask_Session-0.3.0-py2.7.egg/flask_session/sessions.py", line 357, in save_session session_id = self._get_signer(app).sign(want_bytes(session.sid)) AttributeError: 'NoneType' object has no attribute 'sign'

Having issues with loading session using sqlalchemy backend

I noticed there was a fix added for Python 3 to the way session string is handled but I'm still having problems.
data = self.serializer.loads(want_bytes(val)) When this line executes in open_session I'm still not getting my session back. I poked around I noticed pickle is raising exception of type _pickle.UnpicklingError with no message to it.

Python 3.4.0
SQLAlchemy 0.9.8 + MySQL 5.5
Flask 0.10.1

RedisSessionInterface: Flask context not popped on Redis issues

Redis exceptions on open_session make Flask crash painfully, not popping the context correctly (leaking data across requests).
Flask doesn't catch any possible exceptions on the session_interface, resulting in messing up the context.

To reproduce

  1. Set some parameter in flask.g
  2. Initiate RedisSessionInterface on an invalid redis server (redis.exceptions.ConnectionError or any other, we had sometimes Timeout exceptions).
  3. The next requests contains the old flask.g - context not popped

Fix
Ideally Flask uses its interfaces safely - always popping context. Bug created: pallets/flask#2517
Still, I think it would be nice that Flask-Session is safe as well, catching possible redis problems and not letting Flask deal with the exceptions.

Environment
Python version: 2.7.6
Flask version: 0.10.1
Werkzeug version: 0.11.11
Flask-Session: 0.3.1

unicode problem in sqlalchemy interface

I have a problem when I try to store some unicode data with the sqlalchemy interface.

This the error I had.
DataError: (psycopg2.DataError) invalid byte sequence for encoding "UTF8"

I think the type of the column data should be changed to LargeBinary

Session crash?

Hi I tried to clear the session, since I have no idea how to clear all session once logout, but after I did session.clear() I got this error

File "../env/lib/python2.7/site-packages/flask/app.py", line 2000, in __call__ return self.wsgi_app(environ, start_response) File "../env/lib/python2.7/site-packages/flask/app.py", line 1984, in wsgi_app ctx.push() File "../env/lib/python2.7/site-packages/flask/ctx.py", line 332, in push self.session = self.app.open_session(self.request) File "../env/lib/python2.7/site-packages/flask/app.py", line 914, in open_session return self.session_interface.open_session(self, request) File "../env/lib/python2.7/site-packages/flask_session/sessions.py", line 516, in open_session if saved_session and saved_session.expiry <= datetime.utcnow(): TypeError: can't compare datetime.datetime to NoneType

I tried to drop my session db table but still doesnt work

any idea @fengsp ?

Thanks

datetime.timedelta.total_seconds object has no attribute 'total_seconds'

I'm attempting to run Flask-Session 0.1.1 under Python 2.6.6, and am running into an issue right around this line (and others, if I was using those session storage methods):

 File "/var/www/appname/venv/lib/python2.6/site-packages/flask_session/sessions.py", line 118, in save_session
   int(app.permanent_session_lifetime.total_seconds()))
AttributeError: 'datetime.timedelta' object has no attribute 'total_seconds'

It seems that datetime.timedelta.total_seconds was added in Python 2.7.

Is there by chance a 2.6-compatible drop-in replacement you'd consider?

Thanks!

Sessions are being saved to the datastore even if they are not permanant

It seems that non-permanent sessions are being saved in the datastore.

For example, if SESSIONS_PERMANENT config option is set to False, Flask states that they should end when the browser is closed. However, in this plugin, the session is being saved to Redis (or whatever datastore you are using) with the default permanent session lifetime, whether the session is permanent or not. See: https://github.com/fengsp/flask-session/blob/master/flask_session/sessions.py#L166

Is this intended?

If not, I suggest that we add an if statement to check if the session is permanent before we save anything to a datastore.

We have come across an issue with this at my company, we will fork and raise a PR with our intended fix shortly...

Race condition for two requests in close proximity

I spent the whole morning debugging an issue where submitting two requests in close proximity will cause a race condition in the flask-session extension.
I'm using the Redis session interface, but it might affect others as well.

Here is what happens:

  1. Submit two requests that will modify the session.
    E.g. session['my_list'].append('foo') and session['my_list'].append('bar')
  2. Due to the parallelisation of the requests both are executed at the same time
  3. open_session() is called twice before any of the two requests reaches save_session()
  4. The session value for both requests is now IDENTICAL. This is very bad.
  5. save_session() is called by one of the two, then the other. Since the retrieved values in step 4 are identical, one will overwrite the other.

This is roughly what happens in Redis:

GET session:123 -> []
GET session:123 -> []
SETEX session:123 [foo]
SETEX session:123 [bar]

This is what should happen:

GET session:123 -> []
SETEX session:123 foo
GET session:123 -> [foo]
SETEX session:123 [foo, bar]

FileSession time is too short

FileSession time is too short, I found in the File

sessions.py at line 297

self.cache = FileSystemCache (cache_dir, threshold = threshold, mode = mode)

Missing parameters default_timeout, because FileSystemCache default value is 300 seconds.
look at

class FileSystemCache(BaseCache):
   """
   ....
   """
    #: used for temporary files by the FileSystemCache
    _fs_transaction_suffix = '.__wz_cache'

    def __init__(self, cache_dir, threshold=500, default_timeout=300, mode=0o600):
        BaseCache.__init__(self, default_timeout)
        self._path = cache_dir
        self._threshold = threshold
        self._mode = mode

So I think we should use Flask parameter "PERMANENT_SESSION_LIFETIME"

Session failing when used with MongoDB due to datetime error

I'm using session with MongoDB and it fails because of a datetime error.
TypeError: can't compare offset-naive and offset-aware datetimes

  File "/Library/Python/2.7/site-packages/flask/app.py", line 2000, in __call__
    return self.wsgi_app(environ, start_response)
  File "/Library/Python/2.7/site-packages/flask/app.py", line 1984, in wsgi_app
    ctx.push()
  File "/Library/Python/2.7/site-packages/flask/ctx.py", line 332, in push
    self.session = self.app.open_session(self.request)
  File "/Library/Python/2.7/site-packages/flask/app.py", line 914, in open_session
    return self.session_interface.open_session(self, request)
  File "/Library/Python/2.7/site-packages/flask_session/sessions.py", line 411, in open_session
    if document and document.get('expiration') <= datetime.utcnow():
TypeError: can't compare offset-naive and offset-aware datetimes

I had recently faced a similar issue while checking expiry of a token. Handled it with using a different datetime format.

I believe we need to use any other format like:
datetime.datetime.strptime(,"%d %b %Y %I:%M:%S %p")

Mongo Version : 3.4
Flask-Session==0.3.0

New session for every new connection

I'm using Flask-Session and redis for an application im trying to make and im using gunicorn with 4 gevent workers as the production server.
I'm trying to build a counter which should have a seperate session id each time a new browser or tab is opened and each session id is supposed to maintain its own count.

Here's the code that i have till now.

from flask import Flask
import os
from flask.json import jsonify
from multiprocessing import Value
from flask import Flask, session
from flask_session import Session
import redis  
import os


def create_app():
   	    app = Flask(__name__)
    app.secret_key = '123456789012345678901234'
    app.config['SESSION_TYPE'] = 'redis'
    app.config['SESSION_REDIS'] = redis.from_url('localhost:6379')
    # app.config.from_object(__name__)

    sess = Session()
    sess.init_app(app)

    @app.route('/set/')
    def set():
   	     session['key'] = 1
	     return 'ok'

    @app.route('/get/')
    def get():
	    session['key'] = session.get('key','not set') + 1
	    return 'Count: '+ str(session.get('key','not set')) + ', Process ID: ' +str(os.getpid())

    return app

In the 'set' route, im setting the key value to 1 and whenever i go to 'get' the counter value increases.

I'm trying to figure out how to set session id for each new connection( new tab or browser) and then each session id holds it's count. Any help would be appreciated.

PERMANENT_SESSION_LIFETIME Not Enforced with FileSystemSessionInterface

As I understand the documentation, the user's session should be deleted automatically (server-side) when the SESSION_PERMANENT option is enabled and the session has been idle longer than the PERMANENT_SESSION_LIFETIME value. However, in my application the session file is never removed when using the FileSystemSessionInterface.

from flask import Flask, session  
from flask_session import Session, FileSystemSessionInterface  
...  
app.config['SESSION_TYPE'] = 'filesystem'  
app.config['SECRET_KEY'] = 'donthardcodethisvalue!'  
app.config['SESSION_FILE_DIR'] = './my_sessions'  
app.config['SESSION_USE_SIGNER'] = True  
app.config['SESSION_FILE_MODE'] = 0644  
app.config['PERMANENT_SESSION_LIFETIME'] = 30   #timout in seconds  
app.config['SESSION_PERMANENT'] = True  

#create and configure flask-session  
sess = Session()  

#bind app to flask-session  
sess.init_app(app)  

#define routes ...  

However, the session is removed server-side as expected when using the Redis interface. Am I missing something with the FileSystemSessionInterface?

Additionally, looking at the source, it appears that the PERMANENT_SESSION_LIFETIME is never passed to some of the other interfaces such as MongoDB or SQLAlchemy. Is the session automatically expired server-side when using these interfaces?

Don't use pickle for SqlAlchemy backend

Using pickle is a major security flaw, and can be used for remote code execution or opening a shell.

I understand the pickled data doesn't get read from the client, but it's still a bad idea to store it in the database, since if the database server gets compromised, every single app server is compromised as well.

For more information, see: https://www.cs.uic.edu/~s/musings/pickle.html

MongoDBSessionInterface does not work on Python 3.x

MongoDBSessionInterface does not work on Python 3.x due to an exception being raised when the session is read back from MongoDB. This happens due to the str() call in line 401 of sessions.py in the current head (see https://github.com/fengsp/flask-session/blob/master/flask_session/sessions.py#L401), since type(document['val']) == bytes, and casting it to a str makes it unsuitable for pickle.loads. Removing the call to str() resolves the problem.

Add support for decode_responses=True to RedisSessionInterface?

I am using fakeredis as my Redis connection in my unit tests and it offers a decode_responses argument which avoid returning bytes:

>>> from fakeredis import FakeRedis
>>> rds_without, rds_with = FakeRedis(), FakeRedis(decode_responses=True))
>>> rds_without['a'] = 1
>>> rds_with['a'] = 1
>>> rds_without['a'], rds_with['a']
(b'1', '1')
>>> rds_with.keys()
['session:068678b2-4ecd-4747-91f4-624826d85447', 'a']
>>> rds_without.keys()
[b'session:068678b2-4ecd-4747-91f4-624826d85447', b'a']

As far as I can see in my tests your RedisSessionInterface doesn't support this argument and everything comes back as bytes? In fact, I can't do lookups without bytes:

>>> session
<RedisSession {'_permanent': True, b'foo': b'bar'}>
>>> session['foo']
*** KeyError: 'foo'

Session is established and saved for each new request

I just noticed this behavior while using the Filesystem sessions of Flask-Session. On each new request, a new session file is written with a new key.

Take the following example application

from flask import Flask
from flask.ext.session import Session

app = Flask(__name__)
app.config["SECRET_KEY"] = "__replacewithsomethingunique__"
app.config["SESSION_TYPE"] = "filesystem"

Session(app)

app.run(port=8001)

When I run this code and issue several curl requests, I receive a different session cookie header on each request.

$ curl -is localhost:8001 | grep Set-Cookie
Set-Cookie: session=2a2d9266-deaa-4412-82de-48193503534e; Expires=Mon, 12-Oct-2015 17:46:02 GMT; HttpOnly; Path=/

$ curl -is localhost:8001 | grep Set-Cookie
Set-Cookie: session=a98eebd4-909c-4c42-b68c-3cae7750e390; Expires=Mon, 12-Oct-2015 17:46:02 GMT; HttpOnly; Path=/

$ curl -is localhost:8001 | grep Set-Cookie
Set-Cookie: session=e547e8d2-54de-4359-a4a5-bcf206e88c1e; Expires=Mon, 12-Oct-2015 17:46:03 GMT; HttpOnly; Path=/

$ curl -is localhost:8001 | grep Set-Cookie
Set-Cookie: session=69e78241-5c2e-4bf4-936d-35931cb81e8c; Expires=Mon, 12-Oct-2015 17:46:03 GMT; HttpOnly; Path=/

After which the flask_session directory is filled with several session files

$ ls -1 flask_session/
113e38a76a00f2ebb4912fa547d75ec9
3184c223a385dd63ce728b9e8b778f5a
a62fce576b1734cc77fdd1302e815916
b242e7911524d66023836aaf9847b6fd

This differs from the default flask session behavior. By default flask does not send a Set-Cookie header if nothing happens to the session.
Obviously this could cause some trouble.

If you have more question about this issue or if there is something else I can do to help solving it please let me know.

API components to defend against session management vulnerabilities.

Unless I'm missing something, I don't see where this module exposes the necessary APIs to prevent vulnerabilities such as Session Fixation. In a scenario where you need a pre-authenticated session, how would one create a new session, move the contents of the old session over to the new session, remove the old session, and update the cookie to reflect the token for the new session? I realize I can use session.clear() to remove the old session, but that is only 1/4 of the problem. Am I missing something? Or is that logic that has yet to be written?

session.clear() removes expiry field, causing TypeError

Setup: Flask 0.11, SQLAlchemy session interface, python 2.7.x

When using session.clear() to empty a session, say on a logout signal to ensure an empty session record, the expiry field is set to null in the database:

dev=# select session_id,expiry from sessions;
                  session_id                  | expiry
----------------------------------------------+--------
 session:ed53619f-84d7-4985-9383-260aa9817125 |
(1 row)

This causes a TypeError exception on line 516:

    if saved_session and saved_session.expiry <= datetime.utcnow():
        # Delete expired session
        self.db.session.delete(saved_session)
        self.db.session.commit()
        saved_session = None

Work-around solution is to check for saved_session.expiry before comparison:

    if saved_session and (not saved_session.expiry or saved_session.expiry <= datetime.utcnow()):

SqlAlchemy: TypeError if SESSION_PERMANENT=False

Using SqlAlchemy (both with mysql and sqlite) if I set SESSION_PERMANENT to False the system return a TypeError

File "/home/draio/project/venv/lib/python2.7/site-packages/flask_session/sessions.py", line 516, in open_session
     if saved_session and saved_session.expiry <= datetime.utcnow():
 TypeError: can't compare datetime.datetime to NoneType

Changing the SESSION_TYPE in filesystem the system works and the cookie will be deleted when the browser is closed.

On the DB table the session row has the expiry row empty.
Expiry comes from expires variable tha is set on row 547:
expires = self.get_expiration_time(app, session)

get_expiration_time is a flask fuction that returns the expiration date for the session:

 if session.permanent:
            return datetime.utcnow() + app.permanent_session_lifetime

That's why the expiry field on sessions table is empty, a cookie set as non-permanent doesn't have a expiration date. So it's not possible for mysql and sqlite to check a NULL date.

To populate the expiry field in the DB table I changed:
expires = self.get_expiration_time(app, session)
into

expires = self.get_expiration_time(app, session) \
           or datetime.utcnow() + app.permanent_session_lifetime

No more error but if i close the browser the ,session cookie is still there.
That's because the set_cookie function must have expires empty to delete the cookie when browser is closed.

So I changed:
expires = self.get_expiration_time(app, session)
into

expires = self.get_expiration_time(app, session) \
           or datetime.utcnow() + app.permanent_session_lifetime
expires_cookie=expires if self.permanent else ''

And on line 561 I changed:

response.set_cookie(app.session_cookie_name, session_id,
                    expires=expires, httponly=httponly,
                    domain=domain, path=path, secure=secure)

into

response.set_cookie(app.session_cookie_name, session_id,
                    expires=expires_cookie, httponly=httponly,
                    domain=domain, path=path, secure=secure)

I hope that this could by helpful and clear.


UPDATE

Another way, more elegant, to solve the problem is to check self.permanent before checking if saved_session.expire is outdated.

On line 516 change
if saved_session and saved_session.expiry <= datetime.utcnow():
into something like
if self.permanent and saved_session and saved_session.expiry <= datetime.utcnow():

Also this solution works but, if I'm not wrong, in this way the session will never be deleted from the DB table and, more important, it will never be tested. That's could be a security problem.

In the other solution the expiration date is written to the DB. In that case the problem may be that for a time a cookie remains active even if on the browser has already been deleted. I do not know if this could be considered a security problem.


UPDATE IE11 issue

On IE11 you cannot have a Expires=;, otherwise the cookie will never be stored.
For now I solved brutally with an if on

if not saved_session:
     if expires_cookie:
         response.set_cookie(app.session_cookie_name, session_id,
                                          expires=expires_cookie, httponly=httponly,
                                          domain=domain, path=path, secure=secure)
     else:
         response.set_cookie(app.session_cookie_name, session_id,
                                           httponly=httponly,
                                           domain=domain, path=path, secure=secure)

FileSession not thread-safe

FileSession not thread-safe if I use threaded parameter into creating Flask , look as:

app.run (threaded = True)

There are a large number in parallel,

data = self.cache.get (self.key_prefix + sid)

Will return None, but in the file session.py at line 320,

return self.session_class (sid = sid, permanent = self.permanent)

Ah, God, I always wondered why the session will be reset, Now I konw.

Delete function not found

...
self.store.delete({'id': store_id}) row-409 in session.py
...
self.store.delete({'id': store_id}) row-426 in session.py
....

I have changed to remove and everything goes well. (pymongo==3.2.2.)

db.create_all() doesn't create the table

I'm using flask-sqlalchemy and sqlite file and when I create the database with typical db.create_all() all tables are created but sessions

What I'm missing?

Thanks!

SQLAlchemy db.create_all() causing errors

The use of self.db.create_all() in SqlAlchemySessionInterface is causing me some problems:

https://github.com/fengsp/flask-session/blob/master/flask_session/sessions.py#L458

When using two-step invocation, there is no guarantee of an app context available when session.init_app() is run. The call to db.create_all() results in an error like:

RuntimeError: application not registered on db instance and no application bound to current context

Furthermore, I don't think it's the job of Flask-Session to call this method anyway. If the table needs to be created, IMO that needs to be handled by the application developer.

Suggestions:

  1. Just remove the call to db.create_all(); or
  2. Add a configuration option that would allow us to skip this method being called.

If you decide on option 2 above, then IMO the call to db.create_all() should still be replaced by code that only creates the session table. Based on these docs:

http://docs.sqlalchemy.org/en/latest/core/metadata.html

That would look something like the following for SqlAlchemySessionInterface.__init__():

class Session(self.db.model):
...

if create_session_table:
    Session.table.create(db.engine)

I'd be happy to create a PR if you are interested.

session.clear() not work correctly with mongodb

I used session.clear() with mongodb back-end
and delete cookie from client correctly but when user save cookie separately and send to server. I have session with this cookie.
How can solve this problem?

Upgrade from 0.2.3 to 0.3.0 breaks logins on Elastic Beanstalk

Hi,

With Flask 0.11.1, I just upgraded from Flask-session 0.2.3 to 0.3.0.

It breaks login, not on my local machine, but on EB.

On my local machine: a request to /login_required_page redirects to /login, then redirects to /login_required_page.

On Elastic Beanstalk: a request to /login_required_page redirects to /login, then redirects to /login_required_page, then redirects to /login_reqired_page&next=login_required_page.

Logging in again causes the same error.

I am using flask-session for server-side sessions using Postgres.

Session is gone every time a request come

Every time a new request comes in the previous session values that i set is gone. I'm using SESSION_TYPE = 'filesystem' and SESSION_PERMANENT = True as well.

I'm using Free Heroku dyno for my chatbot.

TypeError in Python 3 in calls to .sign(session.sid)

Calls to .sign(session.sid) fail with a TypeError in Python 3; .sign requires a bytes value.

Simplest solution I see: at the top of the file, from itsdangerous import want_bytes, and replace all instances of .sign(session.sid) with .sign(want_bytes(session.sid)).

Using Socket for Redis Session

Apparently setting
SESSION_REDIS = "/var/run/redis/redis.sock"
. . . does not produce magic.

  File "/home/user/Projects/foo/venv/lib/python2.7/site-packages/flask_session/sessions.py", line 131, in open_session
    val = self.redis.get(self.key_prefix + sid)
AttributeError: 'str' object has no attribute 'get'

Am I missing something obvious, or are you not supporting using a socket for redis sessions at this point?

can't compare offset-naive and offset-aware datetimes

I'm using flask-session with MongoDB (with the help of Flask-PyMongo).
Flask-PyMongo uses timezone-aware datetime objects.

From its docs:

Flask-PyMongo always uses timezone-aware datetime objects. That is, it sets the tz_aware parameter to True when creating a connection. The timezone of datetime objects returned from MongoDB will always be UTC.

flask-session, on the other hand, compares the expires value in the document against datetime.utcnow() which is not time zone aware.

Then the above exception is thrown:
TypeError: can't compare offset-naive and offset-aware datetimes

The workaround (that works for me) is to replace this line:

if document and document.get('expiration') <= datetime.utcnow():

with these two lines:

import pytz
if document and document.get('expiration') <= datetime.utcnow().replace(tzinfo=pytz.UTC):

A permanent solution may be to examine self.client.codec_options.tz_aware (which is a boolean) and act accordingly.


flask == 0.12.2
Flask-PyMongo == 0.5.1
Flask-Session == 0.3.1

Type Error when using signed cookies with SQLAlchemy session (Python 3)

If I configured my Flask session to use SQLAlchemy and signed cookies I end up with a Type Error when the first request hits my application.

This is the configuration I used to enable this functionality:

application.config['SQLALCHEMY_DATABASE_URI'] = "sqlite:////tmp/test.db'"
application.secret_key = "some value"
application.config['SESSION_KEY_PREFIX'] = 'test'
application.config['SESSION_USE_SIGNER'] = True
application.config['SESSION_COOKIE_SECURE'] = True
application.config['SESSION_TYPE'] = 'sqlalchemy'
Session(application)
db = SQLAlchemy(application)
db.create_all()

The problem appears to originate from the itsdangerous library, the signer returns bytes string for use as the sid, this is concatenated to the key prefix (which is a unicode string) and results in the Type error (see screenshot). Also if I don't set the key prefix it fails as it tries to append None.

screen shot 2016-05-17 at 13 50 13

session is randomly getting cleared

I'm running flask-session with flask-login with the following versions:

  • Flask 0.12.2
  • Flask-Login 0.4.0
  • Flask-Session 0.3.1
  • Flask-Restless 1.0.0b2.dev0

The user gets authenticated via a user loader function and a few requests work well. But after maybe 3 to 5 page reloads, suddenly the user is logged out and subsequent requests are not authenticated.

In the session file, user_id still exists, but the other session values, like my custom session['server_token'] are getting cleared for some reason. Also, it always happens on an api request afaik to flask-restless. Eventually one request raises a ProcessingException when current_user.is_authenticated is false and then subsequent requests fail.

For config settings I'm using this:

from datetime import timedelta
PERMANENT_SESSION_LIFETIME = timedelta(hours=8)
SESSION_TYPE = 'filesystem'
SESSION_PERMANENT = True
SESSION_KEY_PREFIX = 'gis'
SESSION_COOKIE_HTTPONLY = True
SESSION_USE_SIGNER = True
SESSION_COOKIE_SECURE = True if not DEBUG else False

I'd appreciate any direction someone might have for debugging this.

redis option for json serializer

To use json instead of pickle for serialize, you' d better set a redis instance like this:

from flask_session import Session, RedisSessionInterface

RedisSessionInterface.serializer = json
rds = redis.Redis(decode_responses=True) # make sure utf8
app.config['SESSION_REDIS'] = rds

SQLAlchemy backend creates an incredible number of table entries

I have a maximum of 30 or 50 users (the same users always) using my platform on any given day and I currently (after a couple weeks) have 90k+ entries in my SQLAlchemy table. What creates so many and why are they there, I believe I am using only default configurations.

this is probably something dumb on my end but....

my entire app (from docs):

#!/usr/bin/env python
from flask import Flask, session
from flask.ext.session import Session
from flask import current_app
import pprint

app = Flask(__name__)
# Check Configuration section for more details
#SESSION_TYPE = 'redis'
app.config.from_object('cvms_flask.config')
Session(app)

@app.route('/set/')
def set():
    pprint.pprint(current_app.config)
    session['key'] = 'value'
    return 'ok'

@app.route('/get/')
def get():
    return session.get('key', 'not set')

if __name__ == '__main__':
    app.run()

exception:

Traceback (most recent call last):
  File "/Users/magregor/.virtualenvs/cvms/lib/python3.5/site-packages/flask/app.py", line 1836, in __call__
    return self.wsgi_app(environ, start_response)
  File "/Users/magregor/.virtualenvs/cvms/lib/python3.5/site-packages/flask/app.py", line 1820, in wsgi_app
    response = self.make_response(self.handle_exception(e))
  File "/Users/magregor/.virtualenvs/cvms/lib/python3.5/site-packages/flask/app.py", line 1403, in handle_exception
    reraise(exc_type, exc_value, tb)
  File "/Users/magregor/.virtualenvs/cvms/lib/python3.5/site-packages/flask/_compat.py", line 33, in reraise
    raise value
  File "/Users/magregor/.virtualenvs/cvms/lib/python3.5/site-packages/flask/app.py", line 1817, in wsgi_app
    response = self.full_dispatch_request()
  File "/Users/magregor/.virtualenvs/cvms/lib/python3.5/site-packages/flask/app.py", line 1477, in full_dispatch_request
    rv = self.handle_user_exception(e)
  File "/Users/magregor/.virtualenvs/cvms/lib/python3.5/site-packages/flask/app.py", line 1381, in handle_user_exception
    reraise(exc_type, exc_value, tb)
  File "/Users/magregor/.virtualenvs/cvms/lib/python3.5/site-packages/flask/_compat.py", line 33, in reraise
    raise value
  File "/Users/magregor/.virtualenvs/cvms/lib/python3.5/site-packages/flask/app.py", line 1475, in full_dispatch_request
    rv = self.dispatch_request()
  File "/Users/magregor/.virtualenvs/cvms/lib/python3.5/site-packages/flask/app.py", line 1461, in dispatch_request
    return self.view_functions[rule.endpoint](**req.view_args)
  File "/Users/magregor/src/cisco/cvms/tests/testsession.py", line 16, in set
    session['key'] = 'value'
  File "/Users/magregor/.virtualenvs/cvms/lib/python3.5/site-packages/werkzeug/local.py", line 341, in __setitem__
    self._get_current_object()[key] = value
  File "/Users/magregor/.virtualenvs/cvms/lib/python3.5/site-packages/flask/sessions.py", line 126, in _fail
    raise RuntimeError('the session is unavailable because no secret '
RuntimeError: the session is unavailable because no secret key was set.  Set the secret_key on the application to something unique and secret.

however dumping current_app.config (right before attempting to use the session):

{ #snip
 'RULES_LOGLEVEL': 'DEBUG',
 'SECRET_KEY': '505<hash-snipped/>',
 'SEND_FILE_MAX_AGE_DEFAULT': 43200,
 'SERVER_NAME': None,
#snip }

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.