Skip to content

Commit

Permalink
update docs and add feature tests
Browse files Browse the repository at this point in the history
  • Loading branch information
jamesejr committed Nov 15, 2024
1 parent 429a278 commit 06bf409
Show file tree
Hide file tree
Showing 4 changed files with 48 additions and 0 deletions.
7 changes: 7 additions & 0 deletions CHANGES.rst
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,13 @@ Flask-Security Changelog

Here you can see the full list of changes between each Flask-Security release.

Version 5.6.0
-------------

Features & Improvements
+++++++++++++++++++++++
- (:issue:`1038`) Add support for 'secret_key' rotation

Version 5.5.2
-------------

Expand Down
9 changes: 9 additions & 0 deletions docs/configuration.rst
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,15 @@ These configuration keys are used globally across all features.
This is actually part of Flask - but is used by Flask-Security to sign all tokens.
It is critical this is set to a strong value. For python3 consider using: ``secrets.token_urlsafe()``

.. py:data:: SECRET_KEY_FALLBACKS
This is a list of old secret keys that can still be used to unsign tokens
that were created with previous secret keys.

Default: ``None``.

.. versionadded:: 5.6.0

.. py:data:: SECURITY_BLUEPRINT_NAME
Specifies the name for the Flask-Security blueprint.
Expand Down
1 change: 1 addition & 0 deletions tests/conftest.py
Original file line number Diff line number Diff line change
Expand Up @@ -118,6 +118,7 @@ def app(request: pytest.FixtureRequest) -> SecurityFixture:
app.config["SQLALCHEMY_TRACK_MODIFICATIONS"] = False

app.config["SECURITY_PASSWORD_SALT"] = "salty"
app.config["SECURITY_CONFIRM_SALT"] = "confirm-salty"
# Make this fasthash for most tests - reduces unit test time by 50%
app.config["SECURITY_PASSWORD_SCHEMES"] = ["fasthash", "argon2", "bcrypt"]
app.config["SECURITY_PASSWORD_HASH"] = "fasthash"
Expand Down
31 changes: 31 additions & 0 deletions tests/test_misc.py
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@

import pytest

from itsdangerous import BadTimeSignature
from wtforms.validators import DataRequired, Length

from tests.test_utils import (
Expand Down Expand Up @@ -67,6 +68,7 @@
uia_phone_mapper,
verify_hash,
)
from flask_security.core import _get_serializer

if t.TYPE_CHECKING: # pragma: no cover
from flask.testing import FlaskClient
Expand Down Expand Up @@ -1521,3 +1523,32 @@ def test_simplify_url():
assert s == "/login"
s = simplify_url("https:/myhost/profile", "https://localhost/login")
assert s == "https://localhost/login"


@pytest.mark.parametrize(
"verify_secret_key, verify_fallbacks, should_pass",
[
("new_secret", [], False), # Should fail - only new key
("new_secret", ["old_secret"], True), # Should pass - has fallback
("old_secret", [], True), # Should pass - using original key
("wrong_secret", ["also_wrong"], False), # Should fail - no valid keys
],
ids=["new-key-only", "with-fallback", "original-key", "wrong-keys"],
)
def test_secret_key_fallbacks(app, verify_secret_key, verify_fallbacks, should_pass):
# Create token with original key
app.config["SECRET_KEY"] = "old_secret"
serializer = _get_serializer(app, "CONFIRM")
token = serializer.dumps({"data": "test"})

# Attempt verification with different key configurations
app.config["SECRET_KEY"] = verify_secret_key
app.config["SECRET_KEY_FALLBACKS"] = verify_fallbacks
serializer = _get_serializer(app, "CONFIRM")

if should_pass:
data = serializer.loads(token)
assert data["data"] == "test"
else:
with pytest.raises(BadTimeSignature):
serializer.loads(token)

0 comments on commit 06bf409

Please sign in to comment.