Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Prefix internal session keys with underscore #470

Merged
merged 1 commit into from Feb 6, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
3 changes: 2 additions & 1 deletion CHANGES
Expand Up @@ -5,7 +5,8 @@ Here you can see the full list of changes between each Flask-Login release.

Unreleased
----------
nothing yet
- Prefix authenticated user_id, remember, and remember_seconds in Flask Session
with underscores to prevent accidental usage in application code. #465

Version 1.0.0
-------------
Expand Down
9 changes: 8 additions & 1 deletion flask_login/config.py
Expand Up @@ -42,7 +42,14 @@

#: A set of session keys that are populated by Flask-Login. Use this set to
#: purge keys safely and accurately.
SESSION_KEYS = set(['user_id', 'remember', '_id', '_fresh', 'next'])
SESSION_KEYS = set([
'_user_id',
'_remember',
'_remember_seconds',
'_id',
'_fresh',
'next',
])

#: A set of HTTP methods which are exempt from `login_required` and
#: `fresh_login_required`. By default, this is just ``OPTIONS``.
Expand Down
24 changes: 12 additions & 12 deletions flask_login/login_manager.py
Expand Up @@ -313,7 +313,7 @@ def _load_user(self):
user = None

# Load user from Flask Session
user_id = session.get('user_id')
user_id = session.get('_user_id')
if user_id is not None and self._user_callback is not None:
user = self._user_callback(user_id)

Expand All @@ -323,7 +323,7 @@ def _load_user(self):
cookie_name = config.get('REMEMBER_COOKIE_NAME', COOKIE_NAME)
header_name = config.get('AUTH_HEADER_NAME', AUTH_HEADER_NAME)
has_cookie = (cookie_name in request.cookies and
session.get('remember') != 'clear')
session.get('_remember') != 'clear')
if has_cookie:
cookie = request.cookies[cookie_name]
user = self._load_user_from_remember_cookie(cookie)
Expand Down Expand Up @@ -356,7 +356,7 @@ def _session_protection_failed(self):
for k in SESSION_KEYS:
sess.pop(k, None)

sess['remember'] = 'clear'
sess['_remember'] = 'clear'
session_protected.send(app)
return True

Expand All @@ -365,7 +365,7 @@ def _session_protection_failed(self):
def _load_user_from_remember_cookie(self, cookie):
user_id = decode_cookie(cookie)
if user_id is not None:
session['user_id'] = user_id
session['_user_id'] = user_id
session['_fresh'] = False
user = None
if self._user_callback:
Expand Down Expand Up @@ -396,14 +396,14 @@ def _load_user_from_request(self, request):

def _update_remember_cookie(self, response):
# Don't modify the session unless there's something to do.
if 'remember' not in session and \
if '_remember' not in session and \
current_app.config.get('REMEMBER_COOKIE_REFRESH_EACH_REQUEST'):
session['remember'] = 'set'
session['_remember'] = 'set'

if 'remember' in session:
operation = session.pop('remember', None)
if '_remember' in session:
operation = session.pop('_remember', None)

if operation == 'set' and 'user_id' in session:
if operation == 'set' and '_user_id' in session:
self._set_cookie(response)
elif operation == 'clear':
self._clear_cookie(response)
Expand All @@ -420,13 +420,13 @@ def _set_cookie(self, response):
secure = config.get('REMEMBER_COOKIE_SECURE', COOKIE_SECURE)
httponly = config.get('REMEMBER_COOKIE_HTTPONLY', COOKIE_HTTPONLY)

if 'remember_seconds' in session:
duration = timedelta(seconds=session['remember_seconds'])
if '_remember_seconds' in session:
duration = timedelta(seconds=session['_remember_seconds'])
else:
duration = config.get('REMEMBER_COOKIE_DURATION', COOKIE_DURATION)

# prepare data
data = encode_cookie(text_type(session['user_id']))
data = encode_cookie(text_type(session['_user_id']))

if isinstance(duration, int):
duration = timedelta(seconds=duration)
Expand Down
2 changes: 1 addition & 1 deletion flask_login/test_client.py
Expand Up @@ -15,5 +15,5 @@ def __init__(self, *args, **kwargs):

if user:
with self.session_transaction() as sess:
sess["user_id"] = user.get_id()
sess["_user_id"] = user.get_id()
sess["_fresh"] = fresh
22 changes: 11 additions & 11 deletions flask_login/utils.py
Expand Up @@ -167,19 +167,19 @@ def login_user(user, remember=False, duration=None, force=False, fresh=True):
return False

user_id = getattr(user, current_app.login_manager.id_attribute)()
session['user_id'] = user_id
session['_user_id'] = user_id
session['_fresh'] = fresh
session['_id'] = current_app.login_manager._session_identifier_generator()

if remember:
session['remember'] = 'set'
session['_remember'] = 'set'
if duration is not None:
try:
# equal to timedelta.total_seconds() but works with Python 2.6
session['remember_seconds'] = (duration.microseconds +
(duration.seconds +
duration.days * 24 * 3600) *
10**6) / 10.0**6
session['_remember_seconds'] = (duration.microseconds +
(duration.seconds +
duration.days * 24 * 3600) *
10**6) / 10.0**6
except AttributeError:
raise Exception('duration must be a datetime.timedelta, '
'instead got: {0}'.format(duration))
Expand All @@ -197,8 +197,8 @@ def logout_user():

user = _get_user()

if 'user_id' in session:
session.pop('user_id')
if '_user_id' in session:
session.pop('_user_id')

if '_fresh' in session:
session.pop('_fresh')
Expand All @@ -208,9 +208,9 @@ def logout_user():

cookie_name = current_app.config.get('REMEMBER_COOKIE_NAME', COOKIE_NAME)
if cookie_name in request.cookies:
session['remember'] = 'clear'
if 'remember_seconds' in session:
session.pop('remember_seconds')
session['_remember'] = 'clear'
if '_remember_seconds' in session:
session.pop('_remember_seconds')

user_logged_out.send(current_app._get_current_object(), user=user)

Expand Down
10 changes: 5 additions & 5 deletions test_login.py
Expand Up @@ -202,7 +202,7 @@ def test_login_disabled_is_set(self):
def test_no_user_loader_raises(self):
login_manager = LoginManager(self.app, add_context_processor=True)
with self.app.test_request_context():
session['user_id'] = '2'
session['_user_id'] = '2'
with self.assertRaises(Exception) as cm:
login_manager._load_user()
expected_message = 'Missing user_loader or request_loader'
Expand Down Expand Up @@ -443,7 +443,7 @@ def test_logout_emits_signal(self):
def test_logout_without_current_user(self):
with self.app.test_request_context():
login_user(notch)
del session['user_id']
del session['_user_id']
with listen_to(user_logged_out) as listener:
logout_user()
listener.assert_heard_one(self.app, user=ANY)
Expand Down Expand Up @@ -783,7 +783,7 @@ def test_set_cookie_with_invalid_duration_raises_exception(self):

with self.assertRaises(Exception) as cm:
with self.app.test_request_context():
session['user_id'] = 2
session['_user_id'] = 2
self.login_manager._set_cookie(None)

expected_exception_message = 'REMEMBER_COOKIE_DURATION must be a ' \
Expand Down Expand Up @@ -1036,7 +1036,7 @@ def test_invalid_remember_cookie(self):
with self.app.test_client() as c:
c.get('/login-notch-remember')
with c.session_transaction() as sess:
sess['user_id'] = None
sess['_user_id'] = None
c.set_cookie(domain, self.remember_cookie_name, 'foo')
result = c.get('/username')
self.assertEqual(u'Anonymous', result.data.decode('utf-8'))
Expand Down Expand Up @@ -1322,7 +1322,7 @@ def logout():

@self.login_manager.request_loader
def load_user_from_request(request):
user_id = request.args.get('user_id') or session.get('user_id')
user_id = request.args.get('user_id') or session.get('_user_id')
try:
user_id = int(float(user_id))
except TypeError:
Expand Down