Skip to content
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.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 6 additions & 2 deletions CHANGES.rst
Original file line number Diff line number Diff line change
Expand Up @@ -13,10 +13,11 @@ Features & Improvements
- (:issue:`1206`) Add support for refresh tokens. See :ref:`token_topic`
- (:pr:`1233`) Change :py:data:`SECURITY_TOKEN_MAX_AGE` from an int to a timedelta.
Also - change default from ``never expire`` to 15 minutes.
- (:pr:`1235`) Change default LOGOUT_METHODS to be just ``"POST"``
- (:pr:`1235`) Change default :py:data:`SECURITY_LOGOUT_METHODS` to be just ``"POST"``
- (:issue:`1228`) Change default ``csrf`` and ``tf_validity`` cookie config to ``secure=True``
- (:issue:`1228`) The ``tf_validity`` cookie name is now configurable via :py:data:`SECURITY_TWO_FACTOR_VALIDITY_COOKIE_NAME`
- (:issue:`1237`) Add support for CSRF on logout
- (:pr:`xx`) Convert all _WITHIN configuration variable to use timedelta.

Fixes
+++++
Expand All @@ -27,7 +28,7 @@ Fixes
Docs and Chores
+++++++++++++++
- (:issue:`1208`) Remove support for Pony ORM
- (:pr:`xxx`) Remove deprecated get_token_status() and converted over to check_and_get_token_status()
- (:pr:`1240`) Remove deprecated get_token_status() and converted over to check_and_get_token_status()

Backwards Compatibility Concerns
+++++++++++++++++++++++++++++++++
Expand All @@ -43,6 +44,9 @@ Backwards Compatibility Concerns
has been change to ``secure=True``.
- The default configuration for :py:data:`SECURITY_CSRF_COOKIE` has been
changed to ``secure=True``
- All _WITHIN configuration variables now take a timedelta instead of the
home-grown <#> <period>. The old form is still accepted, with a deprecation
warning, and converted at flask-security app init time into a timedelta.

Notes
+++++
Expand Down
72 changes: 47 additions & 25 deletions docs/configuration.rst
Original file line number Diff line number Diff line change
Expand Up @@ -844,6 +844,9 @@ Login/Logout

Default: ``["POST"]``.

.. versionchanged:: 5.9.0
Default changed to just allowing ``"POST"``.


.. py:data:: SECURITY_POST_LOGIN_VIEW

Expand Down Expand Up @@ -1055,10 +1058,12 @@ Confirmable
Default: ``False``.
.. py:data:: SECURITY_CONFIRM_EMAIL_WITHIN

Specifies the amount of time a user has before their confirmation
link expires. Always pluralize the time unit for this value.
Specifies how long until the confirmation link expires.

Default: ``timedelta(days=2)``.

Default: ``"5 days"``.
.. versionchanged:: 5.9.0
Accepted value changed to a timedelta
.. py:data:: SECURITY_CONFIRM_URL

Specifies the email confirmation URL.
Expand Down Expand Up @@ -1221,10 +1226,12 @@ Recoverable

.. py:data:: SECURITY_RESET_PASSWORD_WITHIN

Specifies the amount of time a user has before their password reset link expires.
Always pluralize the time unit for this value.
Specifies how long until the reset link expires.

Default: ``timedelta(days=1)``.

Default: ``"1 days"``.
.. versionchanged:: 5.9.0
Accepted value changed to a timedelta

.. py:data:: SECURITY_SEND_PASSWORD_RESET_EMAIL

Expand Down Expand Up @@ -1273,10 +1280,12 @@ Change-Email
Default: ``"security/change_email.html"``.
.. py:data:: SECURITY_CHANGE_EMAIL_WITHIN

Specifies the amount of time a user has before their change email
token expires. Always pluralize the time unit for this value.
Specifies how long until the change email token expires.

Default: ``timedelta(hours=2)``.

Default: ``"2 hours"``
.. versionchanged:: 5.9.0
Accepted value changed to a timedelta
.. py:data:: SECURITY_POST_CHANGE_EMAIL_VIEW

Specifies the view to redirect to after a user successfully confirms their new email address.
Expand Down Expand Up @@ -1357,10 +1366,12 @@ Configuration related to the two-factor authentication feature.
Default: ``120``.
.. py:data:: SECURITY_TWO_FACTOR_SETUP_WITHIN

Specifies the amount of time a user has before their two-factor setup
token expires. Always pluralize the time unit for this value.
Specifies how long until the setup token expires.

Default: ``"30 minutes"``
Default: ``timedelta(minutes=30)``.

.. versionchanged:: 5.9.0
Accepted value changed to a timedelta

.. versionadded:: 5.5.0
.. py:data:: SECURITY_TWO_FACTOR_RESCUE_MAIL
Expand Down Expand Up @@ -1458,7 +1469,10 @@ Configuration related to the two-factor authentication feature.

Specifies the expiration of the two-factor validity cookie and verification of the token.

Default: ``"30 Days"``.
Default: ``timedelta(days=30)``.

.. versionchanged:: 5.9.0
Accepted value changed to a timedelta


.. py:data:: SECURITY_TWO_FACTOR_VALIDITY_COOKIE_NAME
Expand Down Expand Up @@ -1612,10 +1626,12 @@ Unified Signin

.. py:data:: SECURITY_US_SETUP_WITHIN

Specifies the amount of time a user has before their setup
token expires. Always pluralize the time unit for this value.
Specifies how long until the setup token expires.

Default: ``"30 minutes"``
Default: ``timedelta(minutes=30)``.

.. versionchanged:: 5.9.0
Accepted value changed to a timedelta

.. py:data:: SECURITY_US_SIGNIN_REPLACES_LOGIN

Expand Down Expand Up @@ -1755,10 +1771,12 @@ This feature is DEPRECATED as of 5.0.0. Please use unified signin feature instea

.. py:data:: SECURITY_LOGIN_WITHIN

Specifies the amount of time a user has before a login link expires.
Always pluralize the time unit for this value.
Specifies how long until the login link expires.

Default: ``timedelta(days=1)``.

Default: ``"1 days"``.
.. versionchanged:: 5.9.0
Accepted value changed to a timedelta

.. py:data:: SECURITY_LOGIN_ERROR_VIEW

Expand Down Expand Up @@ -1849,10 +1867,12 @@ WebAuthn

.. py:data:: SECURITY_WAN_REGISTER_WITHIN

Specifies the amount of time a user has before their register
token expires. Always pluralize the time unit for this value.
Specifies how long until the passkey registration token expires.

Default: ``timedelta(minutes=30)``.

Default: ``"30 minutes"``
.. versionchanged:: 5.9.0
Accepted value changed to a timedelta

.. py:data:: SECURITY_WAN_REGISTER_TIMEOUT

Expand All @@ -1863,10 +1883,12 @@ WebAuthn

.. py:data:: SECURITY_WAN_SIGNIN_WITHIN

Specifies the amount of time a user has before their signin
token expires. Always pluralize the time unit for this value.
Specifies how long until the passkey signin token expires.

Default: ``"1 minutes"``
Default: ``timedelta(minutes=1)``.

.. versionchanged:: 5.9.0
Accepted value changed to a timedelta

.. py:data:: SECURITY_WAN_SIGNIN_TIMEOUT

Expand Down
7 changes: 4 additions & 3 deletions flask_security/change_email.py
Original file line number Diff line number Diff line change
Expand Up @@ -41,12 +41,12 @@
do_flash,
get_message,
get_url,
get_within_delta,
hash_data,
send_mail,
url_for_security,
verify_hash,
view_commit,
td_format,
)

if t.TYPE_CHECKING: # pragma: no cover
Expand Down Expand Up @@ -129,7 +129,7 @@ def change_email_confirm(token):
if expired:
m, c = get_message(
"CHANGE_EMAIL_EXPIRED",
within=cv("CHANGE_EMAIL_WITHIN"),
within=td_format(cv("CHANGE_EMAIL_WITHIN")),
)
else:
m, c = get_message("API_ERROR")
Expand Down Expand Up @@ -187,6 +187,7 @@ def _send_instructions(user, new_email):
user=user,
link=link,
token=token,
within=td_format(cv("CHANGE_EMAIL_WITHIN")),
)

change_email_instructions_sent.send(
Expand All @@ -204,7 +205,7 @@ def _verify_token_status(token):
new_email is still available (and if not return 'invalid').
"""
expired, invalid, state = check_and_get_token_status(
token, "change_email", get_within_delta("CHANGE_EMAIL_WITHIN")
token, "change_email", cv("CHANGE_EMAIL_WITHIN")
)
if invalid or expired:
return expired, invalid, None, None
Expand Down
3 changes: 1 addition & 2 deletions flask_security/confirmable.py
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,6 @@
send_mail,
url_for_security,
check_and_get_token_status,
get_within_delta,
verify_hash,
)

Expand Down Expand Up @@ -84,7 +83,7 @@ def confirm_email_token_status(token):
:param token: The confirmation token
"""
expired, invalid, data = check_and_get_token_status(
token, "confirm", get_within_delta("CONFIRM_EMAIL_WITHIN")
token, "confirm", cv("CONFIRM_EMAIL_WITHIN")
)
if invalid or expired or not data:
return expired, invalid, None
Expand Down
41 changes: 32 additions & 9 deletions flask_security/core.py
Original file line number Diff line number Diff line change
Expand Up @@ -241,10 +241,10 @@
"SEND_PASSWORD_CHANGE_EMAIL": True,
"SEND_PASSWORD_RESET_EMAIL": True,
"SEND_PASSWORD_RESET_NOTICE_EMAIL": True,
"LOGIN_WITHIN": "1 days",
"LOGIN_WITHIN": timedelta(days=1),
"CHANGE_EMAIL": False,
"CHANGE_EMAIL_TEMPLATE": "security/change_email.html",
"CHANGE_EMAIL_WITHIN": "2 hours",
"CHANGE_EMAIL_WITHIN": timedelta(hours=2),
"CHANGE_EMAIL_URL": "/change-email",
"CHANGE_EMAIL_CONFIRM_URL": "/change-email-confirm",
"CHANGE_EMAIL_ERROR_VIEW": None, # spa
Expand All @@ -260,7 +260,7 @@
"TWO_FACTOR_MAIL_VALIDITY": 300,
"TWO_FACTOR_SMS_VALIDITY": 120,
"TWO_FACTOR_ALWAYS_VALIDATE": True,
"TWO_FACTOR_LOGIN_VALIDITY": "30 days",
"TWO_FACTOR_LOGIN_VALIDITY": timedelta(days=30),
"TWO_FACTOR_VALIDITY_SALT": "tf-validity-salt",
"TWO_FACTOR_VALIDITY_COOKIE_NAME": "tf_validity",
"TWO_FACTOR_VALIDITY_COOKIE": {
Expand All @@ -269,7 +269,7 @@
"samesite": "Strict",
},
"TWO_FACTOR_SETUP_SALT": "tf-setup-salt",
"TWO_FACTOR_SETUP_WITHIN": "30 minutes",
"TWO_FACTOR_SETUP_WITHIN": timedelta(minutes=30),
"TWO_FACTOR_RESCUE_EMAIL": True,
"MULTI_FACTOR_RECOVERY_CODES": False,
"MULTI_FACTOR_RECOVERY_CODES_N": 5,
Expand All @@ -285,8 +285,8 @@
"OAUTH_RESPONSE_URL": "/login/oauthresponse",
"OAUTH_VERIFY_START_URL": "/login/oauth-verify-start",
"OAUTH_VERIFY_RESPONSE_URL": "/login/oauth-verify-response",
"CONFIRM_EMAIL_WITHIN": "5 days",
"RESET_PASSWORD_WITHIN": "1 days",
"CONFIRM_EMAIL_WITHIN": timedelta(days=2),
"RESET_PASSWORD_WITHIN": timedelta(days=1),
"LOGIN_WITHOUT_CONFIRMATION": False,
"AUTO_LOGIN_AFTER_CONFIRM": False,
"AUTO_LOGIN_AFTER_RESET": False,
Expand Down Expand Up @@ -372,7 +372,7 @@
"US_MFA_REQUIRED": ["password", "email"],
"US_TOKEN_VALIDITY": 120,
"US_EMAIL_SUBJECT": _("Verification Code"),
"US_SETUP_WITHIN": "30 minutes",
"US_SETUP_WITHIN": timedelta(minutes=30),
"US_SIGNIN_REPLACES_LOGIN": False,
"CACHE_CONTROL": {"private": True, "no-store": True},
"CSRF_PROTECT_MECHANISMS": AUTHN_MECHANISMS,
Expand Down Expand Up @@ -400,11 +400,11 @@
"WAN_REGISTER_TIMEOUT": 60000, # milliseconds
"WAN_REGISTER_TEMPLATE": "security/wan_register.html",
"WAN_REGISTER_URL": "/wan-register",
"WAN_REGISTER_WITHIN": "30 minutes",
"WAN_REGISTER_WITHIN": timedelta(minutes=30),
"WAN_SIGNIN_TIMEOUT": 60000, # milliseconds
"WAN_SIGNIN_TEMPLATE": "security/wan_signin.html",
"WAN_SIGNIN_URL": "/wan-signin",
"WAN_SIGNIN_WITHIN": "1 minutes",
"WAN_SIGNIN_WITHIN": timedelta(minutes=1),
"WAN_DELETE_URL": "/wan-delete",
"WAN_VERIFY_URL": "/wan-verify",
"WAN_VERIFY_TEMPLATE": "security/wan_verify.html",
Expand Down Expand Up @@ -1769,6 +1769,29 @@ def init_app(
seconds=cv("TOKEN_MAX_AGE", app=app)
)

within_conversion = [
"LOGIN_WITHIN",
"CHANGE_EMAIL_WITHIN",
"CONFIRM_EMAIL_WITHIN",
"RESET_PASSWORD_WITHIN",
"TWO_FACTOR_SETUP_WITHIN",
"US_SETUP_WITHIN",
"WAN_REGISTER_WITHIN",
"WAN_SIGNIN_WITHIN",
"TWO_FACTOR_LOGIN_VALIDITY",
]
for key in within_conversion:
within_value = cv(key, app=app)
if not isinstance(within_value, timedelta):
values = within_value.split()
app.config[f"SECURITY_{key}"] = timedelta(**{values[1]: int(values[0])})
warnings.warn(
f"Non timedelta values for SECURITY_{key} are"
f"deprecated as of 5.9",
DeprecationWarning,
stacklevel=2,
)

self.login_manager = _get_login_manager(app, self)
self._phone_util = self._phone_util_cls(app)
self._mail_util = self._mail_util_cls(app)
Expand Down
7 changes: 3 additions & 4 deletions flask_security/passwordless.py
Original file line number Diff line number Diff line change
Expand Up @@ -14,11 +14,10 @@
from .proxies import _security, _datastore
from .signals import login_instructions_sent
from .utils import (
config_value,
config_value as cv,
send_mail,
url_for_security,
check_and_get_token_status,
get_within_delta,
)


Expand All @@ -31,7 +30,7 @@ def send_login_instructions(user):
login_link = url_for_security("token_login", token=token, _external=True)

send_mail(
config_value("EMAIL_SUBJECT_PASSWORDLESS"),
cv("EMAIL_SUBJECT_PASSWORDLESS"),
user.email,
"login_instructions",
user=user,
Expand Down Expand Up @@ -64,7 +63,7 @@ def login_token_status(token):
:param token: The login token
"""
expired, invalid, data = check_and_get_token_status(
token, "login", get_within_delta("LOGIN_WITHIN")
token, "login", cv("LOGIN_WITHIN")
)
if invalid or not data:
return expired, invalid, None
Expand Down
Loading