mirror of https://github.com/pallets/flask.git
Added finer control over the session cookie parameters
This commit is contained in:
parent
23bf2633f6
commit
ccf464189b
1
CHANGES
1
CHANGES
|
@ -42,6 +42,7 @@ Relase date to be decided, codename to be chosen.
|
||||||
pluggable (class based) views.
|
pluggable (class based) views.
|
||||||
- Fixed an issue where the test client if used with the with statement did not
|
- Fixed an issue where the test client if used with the with statement did not
|
||||||
trigger the execution of the teardown handlers.
|
trigger the execution of the teardown handlers.
|
||||||
|
- Added finer control over the session cookie parameters.
|
||||||
|
|
||||||
Version 0.7.3
|
Version 0.7.3
|
||||||
-------------
|
-------------
|
||||||
|
|
|
@ -70,6 +70,20 @@ The following configuration values are used internally by Flask:
|
||||||
very risky).
|
very risky).
|
||||||
``SECRET_KEY`` the secret key
|
``SECRET_KEY`` the secret key
|
||||||
``SESSION_COOKIE_NAME`` the name of the session cookie
|
``SESSION_COOKIE_NAME`` the name of the session cookie
|
||||||
|
``SESSION_COOKIE_DOMAIN`` the domain for the session cookie. If
|
||||||
|
this is not set, the cookie will be
|
||||||
|
valid for all subdomains of
|
||||||
|
``SERVER_NAME``.
|
||||||
|
``SESSION_COOKIE_PATH`` the path for the session cookie. If
|
||||||
|
this is not set the cookie will be valid
|
||||||
|
for all of ``APPLICATION_ROOT`` or if
|
||||||
|
that is not set for ``'/'``.
|
||||||
|
``SESSION_COOKIE_HTTPONLY`` controls if the cookie should be set
|
||||||
|
with the httponly flag. Defaults to
|
||||||
|
`True`.
|
||||||
|
``SESSION_COOKIE_SECURE`` controls if the cookie should be set
|
||||||
|
with the secure flag. Defaults to
|
||||||
|
`False`.
|
||||||
``PERMANENT_SESSION_LIFETIME`` the lifetime of a permanent session as
|
``PERMANENT_SESSION_LIFETIME`` the lifetime of a permanent session as
|
||||||
:class:`datetime.timedelta` object.
|
:class:`datetime.timedelta` object.
|
||||||
``USE_X_SENDFILE`` enable/disable x-sendfile
|
``USE_X_SENDFILE`` enable/disable x-sendfile
|
||||||
|
@ -142,7 +156,9 @@ The following configuration values are used internally by Flask:
|
||||||
|
|
||||||
.. versionadded:: 0.8
|
.. versionadded:: 0.8
|
||||||
``TRAP_BAD_REQUEST_ERRORS``, ``TRAP_HTTP_EXCEPTIONS``,
|
``TRAP_BAD_REQUEST_ERRORS``, ``TRAP_HTTP_EXCEPTIONS``,
|
||||||
``APPLICATION_ROOT``
|
``APPLICATION_ROOT``, ``SESSION_COOKIE_DOMAIN``,
|
||||||
|
``SESSION_COOKIE_PATH``, ``SESSION_COOKIE_HTTPONLY``,
|
||||||
|
``SESSION_COOKIE_SECURE``
|
||||||
|
|
||||||
Configuring from Files
|
Configuring from Files
|
||||||
----------------------
|
----------------------
|
||||||
|
|
|
@ -231,12 +231,16 @@ class Flask(_PackageBoundObject):
|
||||||
'PROPAGATE_EXCEPTIONS': None,
|
'PROPAGATE_EXCEPTIONS': None,
|
||||||
'PRESERVE_CONTEXT_ON_EXCEPTION': None,
|
'PRESERVE_CONTEXT_ON_EXCEPTION': None,
|
||||||
'SECRET_KEY': None,
|
'SECRET_KEY': None,
|
||||||
'SESSION_COOKIE_NAME': 'session',
|
|
||||||
'PERMANENT_SESSION_LIFETIME': timedelta(days=31),
|
'PERMANENT_SESSION_LIFETIME': timedelta(days=31),
|
||||||
'USE_X_SENDFILE': False,
|
'USE_X_SENDFILE': False,
|
||||||
'LOGGER_NAME': None,
|
'LOGGER_NAME': None,
|
||||||
'SERVER_NAME': None,
|
'SERVER_NAME': None,
|
||||||
'APPLICATION_ROOT': None,
|
'APPLICATION_ROOT': None,
|
||||||
|
'SESSION_COOKIE_NAME': 'session',
|
||||||
|
'SESSION_COOKIE_DOMAIN': None,
|
||||||
|
'SESSION_COOKIE_PATH': None,
|
||||||
|
'SESSION_COOKIE_HTTPONLY': True,
|
||||||
|
'SESSION_COOKIE_SECURE': False,
|
||||||
'MAX_CONTENT_LENGTH': None,
|
'MAX_CONTENT_LENGTH': None,
|
||||||
'TRAP_BAD_REQUEST_ERRORS': False,
|
'TRAP_BAD_REQUEST_ERRORS': False,
|
||||||
'TRAP_HTTP_EXCEPTIONS': False
|
'TRAP_HTTP_EXCEPTIONS': False
|
||||||
|
|
|
@ -123,16 +123,33 @@ class SessionInterface(object):
|
||||||
"""Helpful helper method that returns the cookie domain that should
|
"""Helpful helper method that returns the cookie domain that should
|
||||||
be used for the session cookie if session cookies are used.
|
be used for the session cookie if session cookies are used.
|
||||||
"""
|
"""
|
||||||
|
if app.config['SESSION_COOKIE_DOMAIN'] is not None:
|
||||||
|
return app.config['SESSION_COOKIE_DOMAIN']
|
||||||
if app.config['SERVER_NAME'] is not None:
|
if app.config['SERVER_NAME'] is not None:
|
||||||
# chop of the port which is usually not supported by browsers
|
# chop of the port which is usually not supported by browsers
|
||||||
return '.' + app.config['SERVER_NAME'].rsplit(':', 1)[0]
|
return '.' + app.config['SERVER_NAME'].rsplit(':', 1)[0]
|
||||||
|
|
||||||
def get_cookie_path(self, app):
|
def get_cookie_path(self, app):
|
||||||
"""Returns the path for which the cookie should be valid. The
|
"""Returns the path for which the cookie should be valid. The
|
||||||
default implementation uses the value from the ``APPLICATION_ROOT``
|
default implementation uses the value from the SESSION_COOKIE_PATH``
|
||||||
configuration variable or uses ``/`` if it's `None`.
|
config var if it's set, and falls back to ``APPLICATION_ROOT`` or
|
||||||
|
uses ``/`` if it's `None`.
|
||||||
"""
|
"""
|
||||||
return app.config['APPLICATION_ROOT'] or '/'
|
return app.config['SESSION_COOKIE_PATH'] or \
|
||||||
|
app.config['APPLICATION_ROOT'] or '/'
|
||||||
|
|
||||||
|
def get_cookie_httponly(self, app):
|
||||||
|
"""Returns True if the session cookie should be httponly. This
|
||||||
|
currently just returns the value of the ``SESSION_COOKIE_HTTPONLY``
|
||||||
|
config var.
|
||||||
|
"""
|
||||||
|
return app.config['SESSION_COOKIE_HTTPONLY']
|
||||||
|
|
||||||
|
def get_cookie_secure(self, app):
|
||||||
|
"""Returns True if the cookie should be secure. This currently
|
||||||
|
just returns the value of the ``SESSION_COOKIE_SECURE`` setting.
|
||||||
|
"""
|
||||||
|
return app.config['SESSION_COOKIE_SECURE']
|
||||||
|
|
||||||
def get_expiration_time(self, app, session):
|
def get_expiration_time(self, app, session):
|
||||||
"""A helper method that returns an expiration date for the session
|
"""A helper method that returns an expiration date for the session
|
||||||
|
@ -177,9 +194,12 @@ class SecureCookieSessionInterface(SessionInterface):
|
||||||
expires = self.get_expiration_time(app, session)
|
expires = self.get_expiration_time(app, session)
|
||||||
domain = self.get_cookie_domain(app)
|
domain = self.get_cookie_domain(app)
|
||||||
path = self.get_cookie_path(app)
|
path = self.get_cookie_path(app)
|
||||||
|
httponly = self.get_cookie_httponly(app)
|
||||||
|
secure = self.get_cookie_secure(app)
|
||||||
if session.modified and not session:
|
if session.modified and not session:
|
||||||
response.delete_cookie(app.session_cookie_name, path=path,
|
response.delete_cookie(app.session_cookie_name, path=path,
|
||||||
domain=domain)
|
domain=domain)
|
||||||
else:
|
else:
|
||||||
session.save_cookie(response, app.session_cookie_name, path=path,
|
session.save_cookie(response, app.session_cookie_name, path=path,
|
||||||
expires=expires, httponly=True, domain=domain)
|
expires=expires, httponly=httponly,
|
||||||
|
secure=secure, domain=domain)
|
||||||
|
|
|
@ -207,6 +207,28 @@ class BasicFunctionalityTestCase(FlaskTestCase):
|
||||||
rv = app.test_client().get('/', 'http://example.com:8080/')
|
rv = app.test_client().get('/', 'http://example.com:8080/')
|
||||||
self.assert_('path=/bar' in rv.headers['set-cookie'].lower())
|
self.assert_('path=/bar' in rv.headers['set-cookie'].lower())
|
||||||
|
|
||||||
|
def test_session_using_session_settings(self):
|
||||||
|
app = flask.Flask(__name__)
|
||||||
|
app.config.update(
|
||||||
|
SECRET_KEY='foo',
|
||||||
|
SERVER_NAME='www.example.com:8080',
|
||||||
|
APPLICATION_ROOT='/test',
|
||||||
|
SESSION_COOKIE_DOMAIN='.example.com',
|
||||||
|
SESSION_COOKIE_HTTPONLY=False,
|
||||||
|
SESSION_COOKIE_SECURE=True,
|
||||||
|
SESSION_COOKIE_PATH='/'
|
||||||
|
)
|
||||||
|
@app.route('/')
|
||||||
|
def index():
|
||||||
|
flask.session['testing'] = 42
|
||||||
|
return 'Hello World'
|
||||||
|
rv = app.test_client().get('/', 'http://www.example.com:8080/test/')
|
||||||
|
cookie = rv.headers['set-cookie'].lower()
|
||||||
|
self.assert_('domain=.example.com' in cookie)
|
||||||
|
self.assert_('path=/;' in cookie)
|
||||||
|
self.assert_('secure' in cookie)
|
||||||
|
self.assert_('httponly' not in cookie)
|
||||||
|
|
||||||
def test_missing_session(self):
|
def test_missing_session(self):
|
||||||
app = flask.Flask(__name__)
|
app = flask.Flask(__name__)
|
||||||
def expect_exception(f, *args, **kwargs):
|
def expect_exception(f, *args, **kwargs):
|
||||||
|
|
Loading…
Reference in New Issue