From de0802bb83dee4ca9426f994746bdd1a648e2543 Mon Sep 17 00:00:00 2001 From: jwag956 Date: Mon, 27 May 2019 18:35:01 -0700 Subject: [PATCH] chore(build, doc) - Start 3.2.0rc1. Add sphinx-issues so we can easily link to github. Add 3.2.0 changes so far. Reduce line length to 88 which is what Black and others are promoting. Add doc on unauthorized_handler Add doc on utils.get_url and utils.tranform_url. Update minimum versions for pytest packages. Update minimum versions for itsdangerous and passlib. --- .travis.yml | 2 +- AUTHORS | 7 +++++++ CHANGES | 39 ++++++++++++++++++++++++++---------- docs/api.rst | 12 +++++++++++ docs/conf.py | 8 ++++++-- docs/customizing.rst | 4 ++-- docs/features.rst | 2 ++ flask_security/__init__.py | 4 ++-- flask_security/core.py | 6 +++++- flask_security/decorators.py | 8 ++++---- flask_security/utils.py | 4 +++- flask_security/views.py | 12 +++++++---- pytest.ini | 2 +- setup.py | 16 ++++++++++----- 14 files changed, 92 insertions(+), 34 deletions(-) diff --git a/.travis.yml b/.travis.yml index 84e59314..7bbe204f 100644 --- a/.travis.yml +++ b/.travis.yml @@ -64,7 +64,7 @@ script: msgcheck -pwW flask_security/translations/*/LC_MESSAGES/flask_security.po; # run it again with spelling - but dont die on errors echo "Running msgcheck with spell check (ignoring errors)"; - msgcheck -pwW -s str --pwl flask_security/translations/pwl.txt flask_security/translations/*/LC_MESSAGES/flask_security.po || exit 0; + (msgcheck -pwW -s str --pwl flask_security/translations/pwl.txt flask_security/translations/*/LC_MESSAGES/flask_security.po || exit 0); fi after_script: diff --git a/AUTHORS b/AUTHORS index ce653c86..61891bcd 100644 --- a/AUTHORS +++ b/AUTHORS @@ -6,6 +6,11 @@ Development Lead - Matt Wright +Maintainer +`````````` + +- Chris Wagner + Patches and Suggestions ``````````````````````` @@ -39,3 +44,5 @@ Tristan Escalada Vadim Kotov Walt Askew John Paraskevopoulos +Chris Wagner +Eric Regnier diff --git a/CHANGES b/CHANGES index 7245cb0c..cfb0261c 100644 --- a/CHANGES +++ b/CHANGES @@ -3,22 +3,39 @@ Flask-Security Changelog Here you can see the full list of changes between each Flask-Security release. +Version 3.2.0 +------------- + +Released TBD + +- (opr #839) Support caching of authentication token (eregnier). + This adds a new configuration variable SECURITY_USE_VERIFY_PASSWORD_CACHE + which enables a cache (with configurable TTL) for authentication tokens. + This is a big performance boost for those accessing Flask-Security via token + as opposed to session. +- (:pr:`81`) Support for JSON/Single-Page-Application. This completes support + for non-form based access to Flask-Security. See PR for details. (jwag956) +- (:pr:`79` Add POST logout to enhance JSON usage (jwag956). +- (:pr:`73`) Fix get_user for various DBs (jwag956). + This is a more complete fix than in opr #633. +- (:pr:`78`) Add formal openapi API spec (jwag956). + Version 3.1.0 ------------- Released TBD -- Use Security.render_template in mails too (opr #487) -- Optimize DB accesses by using an SQL JOIN when retrieving a user. (opr #679) -- Add base template to security templates (opr #697) -- datastore: get user by numeric identity attribute (opr #633) -- bugfix: support application factory pattern (opr703) -- Make SECURITY_PASSWORD_SINGLE_HASH a list of scheme ignoring double hash (opr #714) -- Allow custom login_manager to be passed in to Flask-Security (opr #717) -- Docs for OAauth2-based custom login manager (opr #727) -- core: make the User model check the password (opr #779) -- Customizable send_mail (opr #730) -- core: fix default for UNAUTHORIZED_VIEW (opr #726) +- (opr #487) Use Security.render_template in mails too (noirbizarre) +- (opr #679) Optimize DB accesses by using an SQL JOIN when retrieving a user. (nfvs) +- (opr #697) Add base template to security templates (grihabor) +- (opr #633) datastore: get user by numeric identity attribute (jirikuncar) +- (opr #703) bugfix: support application factory pattern (briancappello) +- (opr #714) Make SECURITY_PASSWORD_SINGLE_HASH a list of scheme ignoring double hash (noirbizarre ) +- (opr #717) Allow custom login_manager to be passed in to Flask-Security (jaza) +- (opr #727) Docs for OAauth2-based custom login manager (jaza) +- (opr #779) core: make the User model check the password (mklassen) +- (opr #730) Customizable send_mail (abulte) +- (opr #726) core: fix default for UNAUTHORIZED_VIEW (jirijunkar) These should all be backwards compatible. diff --git a/docs/api.rst b/docs/api.rst index 35ee32c8..171a720c 100644 --- a/docs/api.rst +++ b/docs/api.rst @@ -28,6 +28,14 @@ Protecting Views .. autofunction:: flask_security.decorators.auth_token_required +.. autofunction:: flask_security.decorators.auth_required + +.. data:: @security.unauthorized_handler + + If an endpoint fails authentication or authorization from above decorators + (except ``login_required``), a method annotated with this decorator will be called. + For ``login_required`` (which is implemented in Flask-Login) use + **@security.login_manager.unauthorized_handler** User Object Helpers ------------------- @@ -86,6 +94,10 @@ Utils .. autofunction:: flask_security.utils.get_token_status +.. autofunction:: flask_security.utils.get_url + +.. autofunction:: flask_security.utils.transform_url + Signals ------- See the `Flask documentation on signals`_ for information on how to use these diff --git a/docs/conf.py b/docs/conf.py index 72383528..74d1f571 100644 --- a/docs/conf.py +++ b/docs/conf.py @@ -27,7 +27,7 @@ # Add any Sphinx extension module names here, as strings. They can be # extensions coming with Sphinx (named 'sphinx.ext.*') or your custom ones. -extensions = ['sphinx.ext.autodoc', 'sphinx.ext.intersphinx'] +extensions = ['sphinx.ext.autodoc', 'sphinx.ext.intersphinx', 'sphinx_issues'] # Add any paths that contain templates here, relative to this directory. templates_path = ['_templates'] @@ -50,7 +50,7 @@ # built documents. # # The short X.Y version. -version = '3.1.0' +version = '3.2.0' # The full version, including alpha/beta/rc tags. release = version @@ -300,3 +300,7 @@ # Example configuration for intersphinx: refer to the Python standard library. intersphinx_mapping = {'http://docs.python.org/': None} + +# -- Options for spinx-issues --------------------------------------------- +# Github repo +issues_github_path = "jwag956/flask-security" diff --git a/docs/customizing.rst b/docs/customizing.rst index 58abf746..a038d881 100644 --- a/docs/customizing.rst +++ b/docs/customizing.rst @@ -1,5 +1,5 @@ -Customizing Views -================= +Customizing +=========== Flask-Security bootstraps your application with various views for handling its configured features to get you up and running as quickly as possible. However, diff --git a/docs/features.rst b/docs/features.rst index 9bdd9cd7..e56fccc2 100644 --- a/docs/features.rst +++ b/docs/features.rst @@ -119,6 +119,8 @@ JSON is supported for the following operations: * Forgot password requests * Passwordless login requests +In addition, Single-Page-Applications (like those built with Vue, Angular, and +React) are supported via customizable redirect links. Command Line Interface ---------------------- diff --git a/flask_security/__init__.py b/flask_security/__init__.py index 266ba606..55203341 100644 --- a/flask_security/__init__.py +++ b/flask_security/__init__.py @@ -6,7 +6,7 @@ Flask-Security is a Flask extension that aims to add quick and simple security via Flask-Login, Flask-Principal, Flask-WTF, and passlib. - :copyright: (c) 2012 by Matt Wright. + :copyright: (c) 2012-2019 by Matt Wright. :license: MIT, see LICENSE for more details. """ @@ -21,7 +21,7 @@ reset_password_instructions_sent, user_confirmed, user_registered from .utils import login_user, logout_user, url_for_security -__version__ = '3.1.0rc1' +__version__ = '3.2.0rc1' __all__ = ( 'AnonymousUser', 'ConfirmRegisterForm', diff --git a/flask_security/core.py b/flask_security/core.py index a3b45195..52617f17 100644 --- a/flask_security/core.py +++ b/flask_security/core.py @@ -437,7 +437,11 @@ def get_security_payload(self): return {'id': str(self.id)} def get_redirect_qparams(self, existing=None): - """Return user info that will be added to redirect query params.""" + """Return user info that will be added to redirect query params. + + :param existing: A dict that will be updated. + :return: A dict whose keys will be query params and values will be query values. + """ if not existing: existing = {} existing.update({'email': self.email}) diff --git a/flask_security/decorators.py b/flask_security/decorators.py index ec65b140..80860a68 100644 --- a/flask_security/decorators.py +++ b/flask_security/decorators.py @@ -5,7 +5,7 @@ Flask-Security decorators module - :copyright: (c) 2012 by Matt Wright. + :copyright: (c) 2012-2019 by Matt Wright. :license: MIT, see LICENSE for more details. """ @@ -143,7 +143,7 @@ def auth_required(*auth_methods): def dashboard(): return 'Dashboard' - :param auth_methods: Specified mechanisms. + :param auth_methods: Specified mechanisms (token, basic, session) """ login_mechanisms = { 'token': lambda: _check_token(), @@ -183,7 +183,7 @@ def dashboard(): The current user must have both the `admin` role and `editor` role in order to view the page. - :param args: The required roles. + :param roles: The required roles. """ def wrapper(fn): @wraps(fn) @@ -212,7 +212,7 @@ def create_post(): The current user must have either the `editor` role or `author` role in order to view the page. - :param args: The possible roles. + :param roles: The possible roles. """ def wrapper(fn): @wraps(fn) diff --git a/flask_security/utils.py b/flask_security/utils.py index 85f9e710..abd91ce7 100644 --- a/flask_security/utils.py +++ b/flask_security/utils.py @@ -5,7 +5,7 @@ Flask-Security utils module - :copyright: (c) 2012 by Matt Wright. + :copyright: (c) 2012-2019 by Matt Wright. :license: MIT, see LICENSE for more details. """ @@ -236,6 +236,7 @@ def get_url(endpoint_or_url, qparams=None): :param endpoint_or_url: The endpoint name or URL to default to :param qparams: additional query params to add to end of url + :return: URL """ try: return transform_url(url_for(endpoint_or_url), qparams) @@ -267,6 +268,7 @@ def transform_url(url, qparams=None, **kwargs): :param url: url to transform (can be relative) :param qparams: additional query params to add to end of url :param kwargs: pieces of URL to modify - e.g. netloc=localhost:8000 + :return: Modified URL """ if not url: return url diff --git a/flask_security/views.py b/flask_security/views.py index 9ce63dff..700a88ac 100644 --- a/flask_security/views.py +++ b/flask_security/views.py @@ -307,9 +307,12 @@ def forgot_password(): def reset_password(token): """View function that handles a reset password request. - This is usually called via GET as part of an email link and redirects to a reset-password form - It is called via POST to actually update the password (and then redirects to a post reset/login view) - If in either case the token is either invalid or expired it redirects to the 'forgot-password' form. + This is usually called via GET as part of an email link and redirects to + a reset-password form + It is called via POST to actually update the password (and then redirects to + a post reset/login view) + If in either case the token is either invalid or expired it redirects to + the 'forgot-password' form. In the case of non-form based configuration: For GET normal case - redirect to RESET_VIEW?token={token}&email={email} @@ -347,7 +350,8 @@ def reset_password(token): # All good - for forms - redirect to reset password template if _security.redirect_behavior == 'spa': return redirect(get_url(_security.reset_view, - qparams=user.get_redirect_qparams({'token': token}))) + qparams=user.get_redirect_qparams( + {'token': token}))) return _security.render_template( config_value('RESET_PASSWORD_TEMPLATE'), reset_password_form=form, diff --git a/pytest.ini b/pytest.ini index 4ebdb7f7..bc8251f2 100644 --- a/pytest.ini +++ b/pytest.ini @@ -1,3 +1,3 @@ [pytest] addopts = -xrs --cov flask_security --cov-report term-missing --pep8 --flakes --cache-clear -pep8maxlinelength = 120 +pep8maxlinelength = 88 diff --git a/setup.py b/setup.py index 20da193c..0859dd6c 100755 --- a/setup.py +++ b/setup.py @@ -30,11 +30,11 @@ 'pydocstyle>=1.0.0', 'pymysql>=0.9.3', 'pytest-cache>=1.0', - 'pytest-cov>=2.4.0', - 'pytest-flakes>=1.0.1', + 'pytest-cov>=2.5.1', + 'pytest-flakes>=3.0.2', 'pytest-mongo>=1.2.1', 'pytest-pep8>=1.0.6', - 'pytest>=3.3.0', + 'pytest>=3.5.1', 'sqlalchemy>=1.1.0', 'sqlalchemy-utils>=0.33.0', 'werkzeug>=0.12.2' @@ -44,6 +44,7 @@ 'docs': [ 'Flask-Sphinx-Themes>=1.0.1', 'Sphinx>=1.4.2', + 'sphinx-issues>=1.2.0', ], 'tests': tests_require, } @@ -66,8 +67,8 @@ 'Flask-Principal>=0.4.0', 'Flask-WTF>=0.13.1', 'Flask-BabelEx>=0.9.3', - 'itsdangerous>=0.24', - 'passlib>=1.7', + 'itsdangerous>=1.1.0', + 'passlib>=1.7.1', 'cachetools>=3.1.0', ] @@ -85,6 +86,11 @@ maintainer='Chris Wagner', maintainer_email='jwag.wagner@gmail.com', url='https://github.com/jwag956/flask-security', + project_urls={ + "Documentation": "https://flask-security-too.readthedocs.io", + "Code": "https://github.com/jwag956/flask-security", + "Issue tracker": "https://github.com/jwag956/flask-security/issues", + }, packages=packages, zip_safe=False, include_package_data=True,