diff --git a/docs/configuration.rst b/docs/configuration.rst index bc72984f..95ea061a 100644 --- a/docs/configuration.rst +++ b/docs/configuration.rst @@ -214,6 +214,26 @@ Feature Flags change password endpoint. The URL for this endpoint is specified by the ``SECURITY_CHANGE_URL`` configuration option. Defaults to ``False``. +``SECURITY_LOGINABLE`` Specifies if Flask-Security should enable the login + endpoint. The URL for this endpoint is specified by + the ``SECURITY_LOGIN_URL`` configuration option. + This should generally be left enabled, unless you + want to use a custom login endpoint instead of the one + provided by Flask-Security. Note that this flag + does not affect whether or not authentication is + enforced across your site's views. For controlling + that, refer to the ``LOGIN_DISABLED`` flag for + Flask-Login. Defaults to ``True``. +``SECURITY_LOGOUTABLE` Specifies if Flask-Security should enable the logout + endpoint. The URL for this endpoint is specified by + the ``SECURITY_LOGOUT_URL`` configuration option. + This should generally be left enabled, unless you + want to use a custom logout endpoint instead of the + one provided by Flask-Security. Note that this flag + does not affect whether or not authentication is + enforced across your site's views. For controlling + that, refer to the ``LOGIN_DISABLED`` flag for + Flask-Login. Defaults to ``True``. ========================= ====================================================== Email diff --git a/flask_security/core.py b/flask_security/core.py index 597aa00e..a9f029fd 100644 --- a/flask_security/core.py +++ b/flask_security/core.py @@ -90,6 +90,8 @@ 'TRACKABLE': False, 'PASSWORDLESS': False, 'CHANGEABLE': False, + 'LOGINABLE': True, + 'LOGOUTABLE': True, 'SEND_REGISTER_EMAIL': True, 'SEND_PASSWORD_CHANGE_EMAIL': True, 'SEND_PASSWORD_RESET_EMAIL': True, diff --git a/flask_security/views.py b/flask_security/views.py index 25807fbf..052e02cd 100644 --- a/flask_security/views.py +++ b/flask_security/views.py @@ -342,7 +342,8 @@ def create_blueprint(state, import_name): subdomain=state.subdomain, template_folder='templates') - bp.route(state.logout_url, endpoint='logout')(logout) + if state.logoutable: + bp.route(state.logout_url, endpoint='logout')(logout) if state.passwordless: bp.route(state.login_url, @@ -351,7 +352,7 @@ def create_blueprint(state, import_name): bp.route(state.login_url + slash_url_suffix(state.login_url, ''), endpoint='token_login')(token_login) - else: + elif state.loginable: bp.route(state.login_url, methods=['GET', 'POST'], endpoint='login')(login) diff --git a/tests/test_misc.py b/tests/test_misc.py index 81dc6fce..7a6a1531 100644 --- a/tests/test_misc.py +++ b/tests/test_misc.py @@ -32,10 +32,13 @@ def send_email(msg): assert app.mail_sent is True -def test_register_blueprint_flag(app, sqlalchemy_datastore): - app.security = Security(app, datastore=Security, register_blueprint=False) +def test_not_logoutable(app, sqlalchemy_datastore): + app.config['SECURITY_LOGOUTABLE'] = False + app.security = Security(app, datastore=sqlalchemy_datastore) client = app.test_client() - response = client.get('/login') + e = 'matt@lp.com' + authenticate(client, email=e) + response = client.get('/logout') assert response.status_code == 404 @@ -280,3 +283,34 @@ class MyRegisterForm(RegisterForm): def test_without_babel(client): response = client.get('/login') assert b'Login' in response.data + + +def test_register_blueprint_flag(app, sqlalchemy_datastore): + app.security = Security(app, datastore=Security, register_blueprint=False) + client = app.test_client() + response = client.get('/login') + assert response.status_code == 404 + + +def test_loginable(app, sqlalchemy_datastore): + app.security = Security(app, datastore=sqlalchemy_datastore) + client = app.test_client() + response = client.get('/login') + assert response.status_code == 200 + + +def test_not_loginable(app, sqlalchemy_datastore): + app.config['SECURITY_LOGINABLE'] = False + app.security = Security(app, datastore=sqlalchemy_datastore) + client = app.test_client() + response = client.get('/login') + assert response.status_code == 404 + + +def test_logoutable(app, sqlalchemy_datastore): + app.security = Security(app, datastore=sqlalchemy_datastore) + client = app.test_client() + e = 'matt@lp.com' + authenticate(client, email=e) + response = client.get('/logout') + assert response.status_code == 302