Projet

Général

Profil

0003-misc-move-hooks-module-in-utils-package-69720.patch

Benjamin Dauvergne, 18 octobre 2022 20:36

Télécharger (18,9 ko)

Voir les différences:

Subject: [PATCH 03/10] misc: move hooks module in utils package (#69720)

 src/authentic2/api_views.py                |  3 +-
 src/authentic2/cbv.py                      |  2 +-
 src/authentic2/forms/passwords.py          |  3 +-
 src/authentic2/hooks.py                    | 60 +----------------
 src/authentic2/idp/saml/saml2_endpoints.py |  2 +-
 src/authentic2/manager/role_views.py       |  4 +-
 src/authentic2/manager/user_views.py       |  3 +-
 src/authentic2/manager/views.py            |  3 +-
 src/authentic2/utils/hooks.py              | 75 ++++++++++++++++++++++
 src/authentic2/utils/misc.py               |  2 +-
 src/authentic2/views.py                    |  4 +-
 src/authentic2_auth_fc/views.py            |  3 +-
 src/authentic2_auth_oidc/backends.py       |  3 +-
 src/authentic2_idp_cas/views.py            |  2 +-
 src/authentic2_idp_oidc/utils.py           |  3 +-
 src/authentic2_idp_oidc/views.py           |  2 +-
 tests/conftest.py                          |  2 +-
 tests/idp_oidc/test_user_profiles.py       |  2 +-
 18 files changed, 98 insertions(+), 80 deletions(-)
 create mode 100644 src/authentic2/utils/hooks.py
src/authentic2/api_views.py
54 54

  
55 55
from authentic2.compat.drf import action
56 56

  
57
from . import api_mixins, app_settings, decorators, hooks
57
from . import api_mixins, app_settings, decorators
58 58
from .a2_rbac.models import OrganizationalUnit, Role, RoleParenting
59 59
from .a2_rbac.utils import get_default_ou
60 60
from .apps.journal.models import Event
......
62 62
from .journal_event_types import UserLogin, UserRegistration
63 63
from .models import APIClient, Attribute, PasswordReset, Service
64 64
from .passwords import get_password_checker, get_password_strength
65
from .utils import hooks
65 66
from .utils import misc as utils_misc
66 67
from .utils.api import DjangoRBACPermission, NaturalKeyRelatedField
67 68
from .utils.lookups import Unaccent
src/authentic2/cbv.py
20 20
from django.utils.decorators import method_decorator
21 21
from django.views.decorators.csrf import csrf_exempt, ensure_csrf_cookie
22 22

  
23
from . import hooks
23
from .utils import hooks
24 24
from .utils import misc as utils_misc
25 25
from .utils.views import csrf_token_check
26 26

  
src/authentic2/forms/passwords.py
28 28
from authentic2.journal import journal
29 29
from authentic2.passwords import get_min_password_strength
30 30

  
31
from .. import app_settings, hooks, models, validators
31
from .. import app_settings, models, validators
32 32
from ..backends import get_user_queryset
33
from ..utils import hooks
33 34
from ..utils import misc as utils_misc
34 35
from .fields import CheckPasswordField, NewPasswordField, PasswordField, ValidatedEmailField
35 36
from .honeypot import HoneypotForm
src/authentic2/hooks.py
14 14
# You should have received a copy of the GNU Affero General Public License
15 15
# along with this program.  If not, see <http://www.gnu.org/licenses/>.
16 16

  
17
import logging
18

  
19
from django.apps import apps
20
from django.conf import settings
21

  
22
from . import decorators
23
from .utils.cache import GlobalCache
24

  
25

  
26
@GlobalCache
27
def get_hooks(hook_name):
28
    """Return a list of defined hook named a2_hook<hook_name> on AppConfig classes of installed
29
    Django applications.
30

  
31
    Ordering of hooks can be defined using an orer field on the hook method.
32
    """
33
    hooks = []
34
    for app in apps.get_app_configs():
35
        name = 'a2_hook_' + hook_name
36
        if hasattr(app, name):
37
            hooks.append(getattr(app, name))
38
    if hasattr(settings, 'A2_HOOKS') and hasattr(settings.A2_HOOKS, 'items'):
39
        v = settings.A2_HOOKS.get(hook_name)
40
        if callable(v):
41
            hooks.append(v)
42
        v = settings.A2_HOOKS.get('__all__')
43
        if callable(v):
44
            hooks.append(lambda *args, **kwargs: v(hook_name, *args, **kwargs))
45
    hooks.sort(key=lambda hook: getattr(hook, 'order', 0))
46
    return hooks
47

  
48

  
49
@decorators.to_list
50
def call_hooks(hook_name, *args, **kwargs):
51
    '''Call each a2_hook_<hook_name> and return the list of results.'''
52
    logger = logging.getLogger(__name__)
53
    hooks = get_hooks(hook_name)
54
    for hook in hooks:
55
        try:
56
            yield hook(*args, **kwargs)
57
        except Exception:
58
            if getattr(settings, 'A2_HOOKS_PROPAGATE_EXCEPTIONS', False):
59
                raise
60
            logger.exception('exception while calling hook %s', hook)
61

  
62

  
63
def call_hooks_first_result(hook_name, *args, **kwargs):
64
    '''Call each a2_hook_<hook_name> and return the first not None result.'''
65
    logger = logging.getLogger(__name__)
66
    hooks = get_hooks(hook_name)
67
    for hook in hooks:
68
        try:
69
            result = hook(*args, **kwargs)
70
            if result is not None:
71
                return result
72
        except Exception:
73
            if getattr(settings, 'A2_HOOKS_PROPAGATE_EXCEPTIONS', False):
74
                raise
75
            logger.exception('exception while calling hook %s', hook)
17
from .utils.hooks import call_hooks, call_hooks_first_result, get_hooks  # pylint: disable=unused-import
src/authentic2/idp/saml/saml2_endpoints.py
58 58
from django.views.decorators.csrf import csrf_exempt
59 59
from django.views.decorators.http import require_POST
60 60

  
61
from authentic2 import hooks
62 61
from authentic2 import views as a2_views
63 62
from authentic2.attributes_ng.engine import get_attributes
64 63
from authentic2.compat_lasso import lasso
......
109 108
    saml2_urn_to_nidformat,
110 109
    save_key_values,
111 110
)
111
from authentic2.utils import hooks
112 112
from authentic2.utils import misc as utils_misc
113 113
from authentic2.utils.misc import datetime_to_xs_datetime, find_authentication_event
114 114
from authentic2.utils.misc import get_backends as get_idp_backends
src/authentic2/manager/role_views.py
33 33
from django.views.generic import DetailView, FormView, TemplateView
34 34
from django.views.generic.detail import SingleObjectMixin
35 35

  
36
from authentic2 import data_transfer, hooks
36
from authentic2 import data_transfer
37 37
from authentic2.a2_rbac.models import OrganizationalUnit, Permission, Role, RoleParenting
38 38
from authentic2.a2_rbac.utils import get_default_ou
39 39
from authentic2.apps.journal.views import JournalViewWithContext
40 40
from authentic2.forms.profile import modelform_factory
41
from authentic2.utils import crypto
41
from authentic2.utils import crypto, hooks
42 42
from authentic2.utils.misc import redirect
43 43

  
44 44
from . import forms, resources, tables, views
src/authentic2/manager/user_views.py
37 37
from django.views.generic.detail import SingleObjectMixin
38 38
from django.views.generic.edit import BaseFormView
39 39

  
40
from authentic2 import hooks
41 40
from authentic2.a2_rbac.models import OrganizationalUnit, Role, RoleParenting
42 41
from authentic2.a2_rbac.utils import get_default_ou
43 42
from authentic2.apps.journal.views import JournalViewWithContext
44 43
from authentic2.models import Attribute, PasswordReset
45
from authentic2.utils import spooler, switch_user
44
from authentic2.utils import hooks, spooler, switch_user
46 45
from authentic2.utils.misc import make_url, redirect, select_next_url, send_password_reset_mail
47 46
from authentic2_idp_oidc.models import OIDCAuthorization, OIDCClient
48 47

  
src/authentic2/manager/views.py
39 39
from django_tables2 import SingleTableMixin, SingleTableView
40 40
from gadjo.templatetags.gadjo import xstatic
41 41

  
42
from authentic2 import hooks
43 42
from authentic2.a2_rbac.models import OrganizationalUnit
44 43
from authentic2.backends import ldap_backend
45 44
from authentic2.data_transfer import ImportContext, export_site, import_site
46 45
from authentic2.decorators import json as json_view
47 46
from authentic2.forms.profile import modelform_factory
48
from authentic2.utils import crypto
47
from authentic2.utils import crypto, hooks
49 48
from authentic2.utils.misc import batch_queryset, redirect
50 49

  
51 50
from . import app_settings, forms, utils, widgets
src/authentic2/utils/hooks.py
1
# authentic2 - versatile identity manager
2
# Copyright (C) 2010-2019 Entr'ouvert
3
#
4
# This program is free software: you can redistribute it and/or modify it
5
# under the terms of the GNU Affero General Public License as published
6
# by the Free Software Foundation, either version 3 of the License, or
7
# (at your option) any later version.
8
#
9
# This program is distributed in the hope that it will be useful,
10
# but WITHOUT ANY WARRANTY; without even the implied warranty of
11
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12
# GNU Affero General Public License for more details.
13
#
14
# You should have received a copy of the GNU Affero General Public License
15
# along with this program.  If not, see <http://www.gnu.org/licenses/>.
16

  
17
import logging
18

  
19
from django.apps import apps
20
from django.conf import settings
21

  
22
from authentic2 import decorators
23
from authentic2.utils.cache import GlobalCache
24

  
25

  
26
@GlobalCache
27
def get_hooks(hook_name):
28
    """Return a list of defined hook named a2_hook<hook_name> on AppConfig classes of installed
29
    Django applications.
30

  
31
    Ordering of hooks can be defined using an orer field on the hook method.
32
    """
33
    hooks = []
34
    for app in apps.get_app_configs():
35
        name = 'a2_hook_' + hook_name
36
        if hasattr(app, name):
37
            hooks.append(getattr(app, name))
38
    if hasattr(settings, 'A2_HOOKS') and hasattr(settings.A2_HOOKS, 'items'):
39
        v = settings.A2_HOOKS.get(hook_name)
40
        if callable(v):
41
            hooks.append(v)
42
        v = settings.A2_HOOKS.get('__all__')
43
        if callable(v):
44
            hooks.append(lambda *args, **kwargs: v(hook_name, *args, **kwargs))
45
    hooks.sort(key=lambda hook: getattr(hook, 'order', 0))
46
    return hooks
47

  
48

  
49
@decorators.to_list
50
def call_hooks(hook_name, *args, **kwargs):
51
    '''Call each a2_hook_<hook_name> and return the list of results.'''
52
    logger = logging.getLogger(__name__)
53
    hooks = get_hooks(hook_name)
54
    for hook in hooks:
55
        try:
56
            yield hook(*args, **kwargs)
57
        except Exception:
58
            if getattr(settings, 'A2_HOOKS_PROPAGATE_EXCEPTIONS', False):
59
                raise
60
            logger.exception('exception while calling hook %s', hook)
61

  
62

  
63
def call_hooks_first_result(hook_name, *args, **kwargs):
64
    '''Call each a2_hook_<hook_name> and return the first not None result.'''
65
    logger = logging.getLogger(__name__)
66
    hooks = get_hooks(hook_name)
67
    for hook in hooks:
68
        try:
69
            result = hook(*args, **kwargs)
70
            if result is not None:
71
                return result
72
        except Exception:
73
            if getattr(settings, 'A2_HOOKS_PROPAGATE_EXCEPTIONS', False):
74
                raise
75
            logger.exception('exception while calling hook %s', hook)
src/authentic2/utils/misc.py
455 455
def login(request, user, how, nonce=None, record=True, **kwargs):
456 456
    """Login a user model, record the authentication event and redirect to next
457 457
    URL or settings.LOGIN_REDIRECT_URL."""
458
    from .. import hooks
458
    from . import hooks
459 459
    from .service import get_service
460 460
    from .views import check_cookie_works
461 461

  
src/authentic2/views.py
58 58
from authentic2.forms import authentication as authentication_forms
59 59
from authentic2_idp_oidc.models import OIDCAuthorization
60 60

  
61
from . import app_settings, attribute_kinds, cbv, constants, decorators, hooks, models, validators
61
from . import app_settings, attribute_kinds, cbv, constants, decorators, models, validators
62 62
from .a2_rbac.models import OrganizationalUnit as OU
63 63
from .a2_rbac.utils import get_default_ou
64 64
from .forms import passwords as passwords_forms
65 65
from .forms import profile as profile_forms
66 66
from .forms import registration as registration_forms
67 67
from .models import Lock
68
from .utils import crypto
68
from .utils import crypto, hooks
69 69
from .utils import misc as utils_misc
70 70
from .utils import switch_user as utils_switch_user
71 71
from .utils.evaluate import make_condition_context
src/authentic2_auth_fc/views.py
37 37
from requests_oauthlib import OAuth2Session
38 38

  
39 39
from authentic2 import app_settings as a2_app_settings
40
from authentic2 import constants, hooks
40
from authentic2 import constants
41 41
from authentic2.a2_rbac.utils import get_default_ou
42 42
from authentic2.forms.passwords import SetPasswordForm
43 43
from authentic2.models import Attribute, AttributeValue, Lock
44
from authentic2.utils import hooks
44 45
from authentic2.utils import misc as utils_misc
45 46
from authentic2.utils import views as utils_views
46 47
from authentic2.utils.crypto import check_hmac_url, hash_chain, hmac_url
src/authentic2_auth_oidc/backends.py
26 26
from jwcrypto.jwk import JWK
27 27
from jwcrypto.jwt import JWT
28 28

  
29
from authentic2 import app_settings, hooks
29
from authentic2 import app_settings
30 30
from authentic2.a2_rbac.models import OrganizationalUnit
31 31
from authentic2.models import Lock
32
from authentic2.utils import hooks
32 33
from authentic2.utils.crypto import base64url_encode
33 34
from authentic2.utils.template import Template
34 35

  
src/authentic2_idp_cas/views.py
25 25
from django.utils.timezone import now
26 26
from django.views.generic.base import View
27 27

  
28
from authentic2 import hooks
29 28
from authentic2.attributes_ng.engine import get_attributes
30 29
from authentic2.constants import NONCE_FIELD_NAME
30
from authentic2.utils import hooks
31 31
from authentic2.utils.misc import (
32 32
    attribute_values_to_identifier,
33 33
    find_authentication_event,
src/authentic2_idp_oidc/utils.py
27 27
from jwcrypto.jwk import JWK, InvalidJWKValue, JWKSet
28 28
from jwcrypto.jwt import JWT
29 29

  
30
from authentic2 import hooks
31 30
from authentic2.attributes_ng.engine import get_attributes
32
from authentic2.utils import crypto
31
from authentic2.utils import crypto, hooks
33 32
from authentic2.utils.misc import make_url
34 33
from authentic2.utils.template import Template
35 34

  
src/authentic2_idp_oidc/views.py
36 36
from ratelimit.utils import is_ratelimited
37 37

  
38 38
from authentic2 import app_settings as a2_app_settings
39
from authentic2 import hooks
40 39
from authentic2.a2_rbac.models import OrganizationalUnit
41 40
from authentic2.custom_user.models import Profile
42 41
from authentic2.decorators import setting_enabled
43 42
from authentic2.exponential_retry_timeout import ExponentialRetryTimeout
43
from authentic2.utils import hooks
44 44
from authentic2.utils.misc import last_authentication_event, login_require, make_url, redirect
45 45
from authentic2.utils.service import set_service
46 46
from authentic2.utils.view_decorators import check_view_restriction
tests/conftest.py
28 28
from django.db import connection, transaction
29 29
from django.db.migrations.executor import MigrationExecutor
30 30

  
31
from authentic2 import hooks as a2_hooks
32 31
from authentic2.a2_rbac.models import OrganizationalUnit, Role
33 32
from authentic2.a2_rbac.utils import get_default_ou
34 33
from authentic2.authentication import OIDCUser
35 34
from authentic2.manager.utils import get_ou_count
36 35
from authentic2.models import Attribute, Service
36
from authentic2.utils import hooks as a2_hooks
37 37
from authentic2.utils.evaluate import BaseExpressionValidator
38 38
from authentic2_auth_oidc.utils import get_provider_by_issuer
39 39
from authentic2_idp_oidc.models import OIDCClient
tests/idp_oidc/test_user_profiles.py
437 437

  
438 438
    token_url = make_url('oidc-token')
439 439

  
440
    with mock.patch('authentic2.hooks.get_hooks') as get_hooks:
440
    with mock.patch('authentic2.utils.hooks.get_hooks') as get_hooks:
441 441
        get_hooks.return_value = mock_get_hooks('')
442 442
        response = app.post(
443 443
            token_url,
444
-