Skip to content

Commit

Permalink
Added finer control over the session cookie parameters
Browse files Browse the repository at this point in the history
  • Loading branch information
mitsuhiko committed Aug 30, 2011
1 parent 23bf263 commit ccf4641
Show file tree
Hide file tree
Showing 5 changed files with 69 additions and 6 deletions.
1 change: 1 addition & 0 deletions CHANGES
Original file line number Original file line Diff line number Diff line change
Expand Up @@ -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
------------- -------------
Expand Down
18 changes: 17 additions & 1 deletion docs/config.rst
Original file line number Original file line Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -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
---------------------- ----------------------
Expand Down
6 changes: 5 additions & 1 deletion flask/app.py
Original file line number Original file line Diff line number Diff line change
Expand Up @@ -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
Expand Down
28 changes: 24 additions & 4 deletions flask/sessions.py
Original file line number Original file line Diff line number Diff line change
Expand Up @@ -123,16 +123,33 @@ def get_cookie_domain(self, app):
"""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
Expand Down Expand Up @@ -177,9 +194,12 @@ def save_session(self, app, session, response):
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)
22 changes: 22 additions & 0 deletions flask/testsuite/basic.py
Original file line number Original file line Diff line number Diff line change
Expand Up @@ -207,6 +207,28 @@ def index():
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):
Expand Down

0 comments on commit ccf4641

Please sign in to comment.