Skip to content

Commit

Permalink
fix: before_first_request deprecation
Browse files Browse the repository at this point in the history
  • Loading branch information
utnapischtim authored and kpsherva committed Mar 21, 2024
1 parent 878ddea commit 5e1c583
Show file tree
Hide file tree
Showing 10 changed files with 155 additions and 152 deletions.
12 changes: 6 additions & 6 deletions docs/conf.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,18 +2,13 @@
#
# This file is part of Invenio.
# Copyright (C) 2015-2018 CERN.
# Copyright (C) 2022 Graz University of Technology.
# Copyright (C) 2022-2023 Graz University of Technology.
#
# Invenio is free software; you can redistribute it and/or modify it
# under the terms of the MIT License; see LICENSE file for more details.

"""Sphinx configuration."""

import os
import sys

import sphinx.environment

from invenio_accounts import __version__

# -- General configuration ------------------------------------------------
Expand All @@ -38,6 +33,11 @@

celery_task_prefix = "()"

nitpick_ignore = [
("py:attr", "Meta"),
]


# Add any paths that contain templates here, relative to this directory.
templates_path = ["_templates"]

Expand Down
42 changes: 37 additions & 5 deletions invenio_accounts/ext.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
# This file is part of Invenio.
# Copyright (C) 2015-2024 CERN.
# Copyright (C) 2021 TU Wien.
# Copyright (C) 2023 Graz University of Technology.
#
# Invenio is free software; you can redistribute it and/or modify it
# under the terms of the MIT License; see LICENSE file for more details.
Expand Down Expand Up @@ -250,11 +251,6 @@ def _enable_session_activity(self, app):
user_logged_in.connect(csrf_token_reset, app)
user_logged_out.connect(logout_listener, app)
user_logged_out.connect(csrf_token_reset, app)
from .views.security import revoke_session, security
from .views.settings import blueprint

blueprint.route("/security/", methods=["GET"])(security)
blueprint.route("/sessions/revoke/", methods=["POST"])(revoke_session)


class InvenioAccountsREST(InvenioAccounts):
Expand Down Expand Up @@ -333,3 +329,39 @@ def make_session_permanent(self, app):
@app.before_request
def make_session_permanent():
session.permanent = True


def finalize_app(app):
"""Finalize app."""
set_default_config(app)
check_security_settings(app)


def set_default_config(app):
"""Set default values."""
app.config.setdefault(
"ACCOUNTS_SITENAME", app.config.get("THEME_SITENAME", "Invenio")
)
app.config.setdefault(
"ACCOUNTS_BASE_TEMPLATE",
app.config.get("BASE_TEMPLATE", "invenio_accounts/base.html"),
)
app.config.setdefault(
"ACCOUNTS_COVER_TEMPLATE",
app.config.get("COVER_TEMPLATE", "invenio_accounts/base_cover.html"),
)
app.config.setdefault(
"ACCOUNTS_SETTINGS_TEMPLATE",
app.config.get("SETTINGS_TEMPLATE", "invenio_accounts/settings/base.html"),
)


def check_security_settings(app):
"""Warn if session cookie is not secure in production."""
in_production = not (app.debug or app.testing)
secure = app.config.get("SESSION_COOKIE_SECURE")
if in_production and not secure:
app.logger.warning(
"SESSION_COOKIE_SECURE setting must be set to True to prevent the "
"session cookie from being leaked over an insecure channel."
)
23 changes: 2 additions & 21 deletions invenio_accounts/views/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,26 +9,7 @@

"""Invenio-accounts views."""

from flask import abort, current_app, request
from flask_security.views import anonymous_user_required
from flask_security.views import login as base_login

from .settings import blueprint
from .settings import login


@anonymous_user_required
@blueprint.route("/login")
def login(*args, **kwargs):
"""Disable login credential submission if local login is disabled."""
local_login_enabled = current_app.config.get("ACCOUNTS_LOCAL_LOGIN_ENABLED", True)

login_form_submitted = request.method == "POST"
if login_form_submitted and not local_login_enabled:
# only allow GET requests,
# avoid credential submission/login via POST
abort(404)

return base_login(*args, **kwargs)


__all__ = ("blueprint", "login")
__all__ = ("login",)
2 changes: 1 addition & 1 deletion invenio_accounts/views/rest.py
Original file line number Diff line number Diff line change
Expand Up @@ -77,7 +77,7 @@ def role_to_dict(role):
)


def create_blueprint(app):
def create_rest_blueprint(app):
"""Conditionally creates the blueprint."""
blueprint = Blueprint("invenio_accounts_rest_auth", __name__)

Expand Down
19 changes: 0 additions & 19 deletions invenio_accounts/views/security.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,35 +9,16 @@
"""Invenio user management and authentication."""

from flask import abort, current_app, flash, redirect, render_template, request, url_for
from flask_breadcrumbs import register_breadcrumb
from flask_login import login_required
from flask_menu import register_menu
from flask_security import current_user
from invenio_db import db
from invenio_i18n import lazy_gettext as _
from invenio_theme.proxies import current_theme_icons
from speaklater import make_lazy_string

from ..forms import RevokeForm
from ..models import SessionActivity
from ..sessions import delete_session
from .settings import blueprint


@login_required
@register_menu(
blueprint,
"settings.security",
# NOTE: Menu item text (icon replaced by a user icon).
_(
"%(icon)s Security",
icon=make_lazy_string(
lambda: '<i class="{icon}"></i>'.format(icon=current_theme_icons.shield)
),
),
order=2,
)
@register_breadcrumb(blueprint, "breadcrumbs.settings.security", _("Security"))
def security():
"""View for security page."""
sessions = SessionActivity.query_by_user(user_id=current_user.get_id()).all()
Expand Down
120 changes: 46 additions & 74 deletions invenio_accounts/views/settings.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,97 +2,69 @@
#
# This file is part of Invenio.
# Copyright (C) 2015-2018 CERN.
# Copyright (C) 2024 Graz University of Technology.
#
# Invenio is free software; you can redistribute it and/or modify it
# under the terms of the MIT License; see LICENSE file for more details.

"""Invenio user management and authentication."""

from flask import Blueprint, current_app
from flask_breadcrumbs import register_breadcrumb
from flask_menu import current_menu
from flask import Blueprint, abort, current_app, request
from flask_security.views import anonymous_user_required
from flask_security.views import login as base_login
from invenio_i18n import lazy_gettext as _
from invenio_theme.proxies import current_theme_icons
from invenio_theme import menu

blueprint = Blueprint(
"invenio_accounts",
__name__,
url_prefix="/account/settings",
template_folder="../templates",
static_folder="static",
)
from .security import revoke_session, security


@blueprint.record_once
def post_ext_init(state):
"""."""
app = state.app
@anonymous_user_required
def login(*args, **kwargs):
"""Disable login credential submission if local login is disabled."""
local_login_enabled = current_app.config.get("ACCOUNTS_LOCAL_LOGIN_ENABLED", True)

app.config.setdefault(
"ACCOUNTS_SITENAME", app.config.get("THEME_SITENAME", "Invenio")
)
app.config.setdefault(
"ACCOUNTS_BASE_TEMPLATE",
app.config.get("BASE_TEMPLATE", "invenio_accounts/base.html"),
)
app.config.setdefault(
"ACCOUNTS_COVER_TEMPLATE",
app.config.get("COVER_TEMPLATE", "invenio_accounts/base_cover.html"),
)
app.config.setdefault(
"ACCOUNTS_SETTINGS_TEMPLATE",
app.config.get("SETTINGS_TEMPLATE", "invenio_accounts/settings/base.html"),
)
login_form_submitted = request.method == "POST"
if login_form_submitted and not local_login_enabled:
# only allow GET requests,
# avoid credential submission/login via POST
abort(404)

return base_login(*args, **kwargs)

@blueprint.before_app_first_request
def init_menu():
"""Initialize menu before first request."""
# Register root breadcrumbs
item = current_menu.submenu("breadcrumbs.settings")
item.register("invenio_userprofiles.profile", _("Account"))
if current_app.config.get("ACCOUNTS_REGISTER_BLUEPRINT") is False:
return

# - Register menu
# - Change password
if current_app.config.get("SECURITY_CHANGEABLE", True):
view_name = "{}.change_password".format(
current_app.config["SECURITY_BLUEPRINT_NAME"]
)
def create_settings_blueprint(app):
"""Create settings blueprint."""
blueprint = Blueprint(
"invenio_accounts",
__name__,
url_prefix="/account/settings",
template_folder="../templates",
static_folder="static",
)

item = current_menu.submenu("settings.change_password")
item.register(
view_name,
# NOTE: Menu item text (icon replaced by a key icon).
_(
"%(icon)s Change password",
icon=('<i class="{icon}"></i>'.format(icon=current_theme_icons.key)),
),
order=1,
)
icons = app.extensions["invenio-theme"].icons

# Breadcrumb for change password
#
# The breadcrumbs works by decorating the view functions with a
# __breadcrumb__ field. Since the change password view is defined in
# Flask-Security, we need to this hack to in order to decorate the view
# function with the __breadcrumb__ field.
decorator = register_breadcrumb(
current_app, "breadcrumbs.settings.change_password", _("Change password")
)
current_app.view_functions[view_name] = decorator(
current_app.view_functions[view_name]
blueprint.add_url_rule("/login", view_func=login)

if app.config["ACCOUNTS_SESSION_ACTIVITY_ENABLED"]:
blueprint.add_url_rule("/security", view_func=security, methods=["GET"])
blueprint.add_url_rule(
"/sessions/revoke", view_func=revoke_session, methods=["POST"]
)

menu.submenu("settings.security").register(
endpoint="invenio_accounts.security",
text=_("%(icon)s Security", icon=f'<i class="{icons.shield}"></i>'),
order=2,
)

@blueprint.before_app_first_request
def check_security_settings():
"""Warn if session cookie is not secure in production."""
in_production = not (current_app.debug or current_app.testing)
secure = current_app.config.get("SESSION_COOKIE_SECURE")
if in_production and not secure:
current_app.logger.warning(
"SESSION_COOKIE_SECURE setting must be set to True to prevent the "
"session cookie from being leaked over an insecure channel."
# - Register menu
# - Change password
if app.config.get("SECURITY_CHANGEABLE", True):
menu.submenu("settings.change_password").register(
endpoint=f"{app.config['SECURITY_BLUEPRINT_NAME']}.change_password",
text=_("%(icon)s Change password", icon=f'<i class="{icons.key}"></i>'),
order=1,
)

return blueprint
6 changes: 4 additions & 2 deletions setup.cfg
Original file line number Diff line number Diff line change
Expand Up @@ -71,9 +71,11 @@ invenio_base.api_apps =
invenio_base.apps =
invenio_accounts_ui = invenio_accounts:InvenioAccountsUI
invenio_base.blueprints =
invenio_accounts = invenio_accounts.views.settings:blueprint
invenio_accounts = invenio_accounts.views.settings:create_settings_blueprint
invenio_base.api_blueprints =
invenio_accounts_rest_auth = invenio_accounts.views.rest:create_blueprint
invenio_accounts_rest_auth = invenio_accounts.views.rest:create_rest_blueprint
invenio_base.finalize_app =
invenio_accounts = invenio_accounts.ext:finalize_app
invenio_celery.tasks =
invenio_accounts = invenio_accounts.tasks
invenio_db.alembic =
Expand Down
Loading

0 comments on commit 5e1c583

Please sign in to comment.