Skip to content

Commit

Permalink
Support key rotation; do not re-use serializer (#44)
Browse files Browse the repository at this point in the history
  • Loading branch information
jace committed Aug 5, 2020
1 parent 910965a commit 24ff881
Show file tree
Hide file tree
Showing 3 changed files with 32 additions and 8 deletions.
5 changes: 3 additions & 2 deletions .travis.yml
Original file line number Diff line number Diff line change
@@ -1,10 +1,11 @@
sudo: false
language: python
python:
- "2.7"
- "3.6"
- "3.7"
- "3.8"
# command to install dependencies
install:
- pip install six --upgrade --ignore-installed
- python setup.py install
- pip install -r test_requirements.txt
# command to run tests
Expand Down
34 changes: 28 additions & 6 deletions flask_lastuser/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,7 @@

import requests

from coaster.app import KeyRotationWrapper
from coaster.auth import add_auth_attribute, current_auth, request_has_auth
from coaster.utils import getbool, is_collection, utcnow
from coaster.views import get_current_url, get_next_url
Expand Down Expand Up @@ -205,7 +206,10 @@ def before_request(self):
# If we have a Lastuser cookie, it overrides the user tokens in the session
if 'lastuser' in request.cookies:
try:
lastuser_cookie, lastuser_cookie_headers = config['serializer'].loads(
(
lastuser_cookie,
lastuser_cookie_headers,
) = self.lastuser.cookie_serializer().loads(
request.cookies['lastuser'], return_header=True
)
except itsdangerous.BadSignature:
Expand Down Expand Up @@ -436,10 +440,21 @@ def init_app(self, app):
'LASTUSER_USE_SESSIONS', True
)

# Setup cookie serializer
app.lastuser_config['serializer'] = itsdangerous.JSONWebSignatureSerializer(
app.config.get('LASTUSER_SECRET_KEY') or app.config['SECRET_KEY']
)
if 'LASTUSER_SECRET_KEYS' not in app.config:
app.logger.warning("LASTUSER_SECRET_KEYS not found in config")
if 'LASTUSER_SECRET_KEY' in app.config:
app.logger.warning("Upgrading LASTUSER_SECRET_KEY into a list")
app.config['LASTUSER_SECRET_KEYS'] = [app.config['LASTUSER_SECRET_KEY']]
elif 'SECRET_KEYS' in app.config:
app.logger.warning("Using SECRET_KEYS instead")
app.config['LASTUSER_SECRET_KEYS'] = app.config['SECRET_KEYS']
elif app.config['SECRET_KEY']:
app.logger.warning("Using SECRET_KEY instead")
app.config['LASTUSER_SECRET_KEYS'] = [app.config['SECRET_KEY']]
else:
raise ValueError(
"LASTUSER_SECRET_KEYS is not in config and no substitute was found"
)

# Register known external resources provided by Lastuser itself
with app.app_context(): # Required by `self.endpoint_url`
Expand Down Expand Up @@ -475,6 +490,13 @@ def init_app(self, app):
app.before_request(self.before_request)
app.after_request(self.after_request)

def cookie_serializer(self):
# Create a cookie serializer for one-time use
return KeyRotationWrapper(
itsdangerous.JSONWebSignatureSerializer,
current_app.config['LASTUSER_SECRET_KEYS'],
)

@property
def login_beacon_iframe_endpoint(self):
# Legacy property used in Baseframe
Expand Down Expand Up @@ -521,7 +543,7 @@ def after_request(self, response):
expires = utcnow() + timedelta(days=365)
response.set_cookie(
'lastuser',
value=current_app.lastuser_config['serializer'].dumps(
value=self.cookie_serializer().dumps(
current_auth.cookie, header_fields={'v': 1}
),
# Keep this cookie for a year.
Expand Down
1 change: 1 addition & 0 deletions tests/test_mergeuser.py
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@ def setUp(self):
self.app.config['LASTUSER_SERVER'] = 'http://lastuser.testing'
self.app.config['LASTUSER_CLIENT_ID'] = 'client_id'
self.app.config['LASTUSER_CLIENT_SECRET'] = 'client_secret'
self.app.config['LASTUSER_SECRET_KEYS'] = ['random_key']

self.lastuser = Lastuser(self.app)
self.lastuser.init_usermanager(UserManager(db, User, Team))
Expand Down

0 comments on commit 24ff881

Please sign in to comment.