Projet

Général

Profil

0001-misc-remove-dead-authenticators-code-66853.patch

Valentin Deniaud, 21 juillet 2022 11:59

Télécharger (13,7 ko)

Voir les différences:

Subject: [PATCH] misc: remove dead authenticators code (#66853)

 src/authentic2/app_settings.py               |  2 -
 src/authentic2/apps/authenticators/models.py |  4 -
 src/authentic2/authenticators.py             | 49 -----------
 src/authentic2/settings.py                   |  1 -
 src/authentic2/utils/misc.py                 | 66 ++++++---------
 src/authentic2/views.py                      | 85 ++++++--------------
 6 files changed, 49 insertions(+), 158 deletions(-)
 delete mode 100644 src/authentic2/authenticators.py
src/authentic2/app_settings.py
174 174
        default=True, definition='Check username uniqueness on registration'
175 175
    ),
176 176
    IDP_BACKENDS=(),
177
    AUTH_FRONTENDS=(),
178
    AUTH_FRONTENDS_KWARGS={},
179 177
    VALID_REFERERS=Setting(default=(), definition='List of prefix to match referers'),
180 178
    A2_OPENED_SESSION_COOKIE_NAME=Setting(default='A2_OPENED_SESSION', definition='Authentic session open'),
181 179
    A2_OPENED_SESSION_COOKIE_DOMAIN=Setting(default=None),
src/authentic2/apps/authenticators/models.py
102 102
                'value': value,
103 103
            }
104 104

  
105
    @property
106
    def priority(self):
107
        return self.order
108

  
109 105
    def shown(self, ctx=()):
110 106
        if not self.show_condition:
111 107
            return True
src/authentic2/authenticators.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 .utils.evaluate import evaluate_condition
20

  
21
logger = logging.getLogger(__name__)
22

  
23

  
24
class BaseAuthenticator:
25
    how = ()
26

  
27
    def __init__(self, show_condition=None, **kwargs):
28
        self.show_condition = show_condition
29

  
30
    def get_show_condition(self, instance_id=None):
31
        if isinstance(self.show_condition, dict):
32
            if instance_id and instance_id in self.show_condition:
33
                return self.show_condition[instance_id]
34
        else:
35
            return self.show_condition
36

  
37
    def shown(self, instance_id=None, ctx=()):
38
        show_condition = self.get_show_condition(instance_id)
39
        if not show_condition:
40
            return True
41
        ctx = dict(ctx, id=instance_id)
42
        try:
43
            return evaluate_condition(show_condition, ctx, on_raise=True)
44
        except Exception as e:
45
            logger.error(e)
46
            return False
47

  
48
    def get_identifier(self):
49
        return self.id
src/authentic2/settings.py
187 187
# Authentication settings
188 188
###########################
189 189
AUTH_USER_MODEL = 'custom_user.User'
190
AUTH_FRONTENDS = plugins.register_plugins_authenticators()
191 190

  
192 191
###########################
193 192
# RBAC settings
src/authentic2/utils/misc.py
139 139
    return list
140 140

  
141 141

  
142
def load_backend(path, kwargs):
142
def load_backend(path):
143 143
    '''Load an IdP backend by its module path'''
144 144
    i = path.rfind('.')
145 145
    module, attr = path[:i], path[i + 1 :]
......
155 155
        cls = getattr(mod, attr)
156 156
    except AttributeError:
157 157
        raise ImproperlyConfigured('Module "%s" does not define a "%s" idp backend' % (module, attr))
158
    backend_kwargs = {}
159
    if hasattr(cls, 'id'):
160
        backend_kwargs.update(kwargs.get(cls.id, {}))
161
    return cls(**backend_kwargs)
158
    return cls()
162 159

  
163 160

  
164
def get_backends(setting_name='IDP_BACKENDS'):
161
def get_backends():
165 162
    '''Return the list of enabled cleaned backends.'''
166 163
    backends = []
167
    if setting_name == 'AUTH_FRONTENDS':
168
        from authentic2.apps.authenticators.models import BaseAuthenticator, LoginPasswordAuthenticator
169 164

  
170
        backends = list(
171
            BaseAuthenticator.authenticators.filter(enabled=True).exclude(slug='password-authenticator')
172
        )
173
        password_backend, dummy = LoginPasswordAuthenticator.objects.get_or_create(
174
            slug='password-authenticator',
175
            defaults={'enabled': True},
176
        )
177
        if password_backend.enabled:
178
            backends.append(password_backend)
179

  
180
    for backend_path in getattr(app_settings, setting_name):
165
    for backend_path in app_settings.IDP_BACKENDS:
181 166
        kwargs = {}
182 167
        if not isinstance(backend_path, str):
183 168
            backend_path, kwargs = backend_path
184
        kwargs_settings = getattr(app_settings, setting_name + '_KWARGS', {})
185
        backend = load_backend(backend_path, kwargs_settings)
186
        # If no enabled method is defined on the backend, backend enabled by default.
187
        if hasattr(backend, 'enabled') and not backend.enabled():
188
            continue
189
        if backend_path in kwargs_settings:
190
            kwargs.update(kwargs_settings[backend_path])
191
        # Clean id and name for legacy support
192
        if hasattr(backend, 'id'):
193
            if callable(backend.id):
194
                backend.id = backend.id()
195
        else:
196
            backend.id = None
197
        if hasattr(backend, 'name'):
198
            if callable(backend.name):
199
                backend.name = backend.name()
200
        else:
201
            backend.name = None
202
        if not hasattr(backend, 'priority'):
203
            backend.priority = 999  # backend with undefined priority go last
204
        if backend.id and backend.id in kwargs_settings:
205
            kwargs.update(kwargs_settings[backend.id])
169
        backend = load_backend(backend_path)
206 170
        backend.__dict__.update(kwargs)
207 171
        backends.append(backend)
208
    # Order backends list with backend priority
209
    backends.sort(key=lambda backend: backend.priority)
172

  
173
    return backends
174

  
175

  
176
def get_authenticators():
177
    from authentic2.apps.authenticators.models import BaseAuthenticator, LoginPasswordAuthenticator
178

  
179
    backends = list(
180
        BaseAuthenticator.authenticators.filter(enabled=True).exclude(slug='password-authenticator')
181
    )
182
    password_backend, dummy = LoginPasswordAuthenticator.objects.get_or_create(
183
        slug='password-authenticator',
184
        defaults={'enabled': True},
185
    )
186
    if password_backend.enabled:
187
        backends.append(password_backend)
188

  
189
    backends.sort(key=lambda backend: backend.order)
210 190
    return backends
211 191

  
212 192

  
src/authentic2/views.py
361 361
        redirect_to = settings.LOGIN_REDIRECT_URL
362 362
    nonce = request.GET.get(constants.NONCE_FIELD_NAME)
363 363

  
364
    authenticators = utils_misc.get_backends('AUTH_FRONTENDS')
364
    authenticators = utils_misc.get_authenticators()
365 365

  
366 366
    blocks = []
367 367

  
......
382 382
    for authenticator in authenticators:
383 383
        if methods and not set(authenticator.how) & set(methods):
384 384
            continue
385
        # Legacy API
386
        if not hasattr(authenticator, 'login'):
387
            fid = authenticator.get_identifier()
388
            name = authenticator.name
389
            form_class = authenticator.form()
390
            submit_name = 'submit-%s' % fid
391
            block = {'id': fid, 'name': name, 'authenticator': authenticator}
392
            if request.method == 'POST' and submit_name in request.POST:
393
                form = form_class(data=request.POST)
394
                if form.is_valid():
395
                    return authenticator.post(request, form, nonce, redirect_to)
396
                block['form'] = form
397
            else:
398
                block['form'] = form_class()
399
            blocks.append(block)
400
        else:  # New frontends API
401
            auth_blocks = []
402
            parameters = {'request': request, 'context': context}
403
            login_hint = set(request.session.get('login-hint', []))
404
            show_ctx = make_condition_context(request=request, login_hint=login_hint)
405
            service = get_service(request)
406
            if service:
407
                show_ctx['service_ou_slug'] = service.ou and service.ou.slug
408
                show_ctx['service_slug'] = service.slug
409
                show_ctx['service'] = service
410
            else:
411
                show_ctx['service_ou_slug'] = ''
412
                show_ctx['service_slug'] = ''
413
                show_ctx['service'] = None
414
            # check if the authenticator has multiple instances
415
            if hasattr(authenticator, 'instances'):
416
                for instance_id, instance in authenticator.instances(**parameters):
417
                    parameters['instance'] = instance
418
                    parameters['instance_id'] = instance_id
419
                    if not authenticator.shown(instance_id=instance_id, ctx=show_ctx):
420
                        continue
421
                    context['block_index'] = len(blocks)
422
                    block = utils_misc.get_authenticator_method(authenticator, 'login', parameters)
423
                    # update block id in order to separate instances
424
                    block['id'] = '%s_%s' % (block['id'], instance_id)
425
                    auth_blocks.append(block)
426
            else:
427
                if authenticator.shown(ctx=show_ctx):
428
                    context['block_index'] = len(blocks)
429
                    auth_blocks.append(
430
                        utils_misc.get_authenticator_method(authenticator, 'login', parameters)
431
                    )
432
            # If a login frontend method returns an HttpResponse with a status code != 200
433
            # this response is returned.
434
            for block in auth_blocks:
435
                if block:
436
                    if block['status_code'] != 200:
437
                        return block['response']
438
                    blocks.append(block)
385
        auth_blocks = []
386
        parameters = {'request': request, 'context': context}
387
        login_hint = set(request.session.get('login-hint', []))
388
        show_ctx = make_condition_context(request=request, login_hint=login_hint)
389
        service = get_service(request)
390
        if service:
391
            show_ctx['service_ou_slug'] = service.ou and service.ou.slug
392
            show_ctx['service_slug'] = service.slug
393
            show_ctx['service'] = service
394
        else:
395
            show_ctx['service_ou_slug'] = ''
396
            show_ctx['service_slug'] = ''
397
            show_ctx['service'] = None
398
        if authenticator.shown(ctx=show_ctx):
399
            context['block_index'] = len(blocks)
400
            auth_blocks.append(utils_misc.get_authenticator_method(authenticator, 'login', parameters))
401
        # If a login frontend method returns an HttpResponse with a status code != 200
402
        # this response is returned.
403
        for block in auth_blocks:
404
            if block:
405
                if block['status_code'] != 200:
406
                    return block['response']
407
                blocks.append(block)
439 408

  
440 409
    # run the only available authenticator if able to autorun
441 410
    if len(blocks) == 1:
......
455 424
        context.update(
456 425
            {'submit_name': 'submit-%s' % fid, redirect_field_name: redirect_to, 'form': block['form']}
457 426
        )
458
        if hasattr(authenticator, 'get_context'):
459
            context.update(authenticator.get_context())
460 427
        sub_template_name = authenticator.template()
461 428
        block['content'] = render_to_string(sub_template_name, context, request=request)
462 429

  
......
512 479

  
513 480
    def get_context_data(self, **kwargs):
514 481
        context = super().get_context_data(**kwargs)
515
        frontends = utils_misc.get_backends('AUTH_FRONTENDS')
482
        frontends = utils_misc.get_authenticators()
516 483

  
517 484
        request = self.request
518 485

  
......
1163 1130
        parameters = {'request': self.request, 'context': context}
1164 1131
        blocks = [
1165 1132
            utils_misc.get_authenticator_method(authenticator, 'registration', parameters)
1166
            for authenticator in utils_misc.get_backends('AUTH_FRONTENDS')
1133
            for authenticator in utils_misc.get_authenticators()
1167 1134
        ]
1168 1135
        context['frontends'] = collections.OrderedDict((block['id'], block) for block in blocks if block)
1169 1136
        return context
1170
-