Projet

Général

Profil

0001-auth-separate-OIDC-providers-in-blocks-on-login-page.patch

Serghei Mihai, 28 novembre 2019 17:42

Télécharger (6,28 ko)

Voir les différences:

Subject: [PATCH] auth: separate OIDC providers in blocks on login page
 (#31259)

 src/authentic2/views.py                       | 28 ++++++++++++------
 src/authentic2_auth_oidc/authenticators.py    | 14 +++++++--
 .../templates/authentic2_auth_oidc/login.html | 10 +++----
 tests/test_auth_oidc.py                       | 29 +++++++++++++++++++
 4 files changed, 64 insertions(+), 17 deletions(-)
src/authentic2/views.py
320 320
                block['form'] = form_class()
321 321
            blocks.append(block)
322 322
        else:  # New frontends API
323
            auth_blocks = []
323 324
            parameters = {'request': request,
324 325
                          'context': context}
325
            block = utils.get_authenticator_method(authenticator, 'login', parameters)
326
            # check if the authenticator has multiple instances
327
            if hasattr(authenticator, 'instances'):
328
                for instance_id, instance in authenticator.instances:
329
                    parameters['instance'] = instance
330
                    block = utils.get_authenticator_method(authenticator, 'login', parameters)
331
                    # update block id in order to separate instances
332
                    block['id'] = '%s_%s' % (block['id'], instance_id)
333
                    auth_blocks.append(block)
334
            else:
335
                auth_blocks.append(utils.get_authenticator_method(authenticator, 'login', parameters))
326 336
            # If a login frontend method returns an HttpResponse with a status code != 200
327 337
            # this response is returned.
328
            if block:
329
                if block['status_code'] != 200:
330
                    return block['response']
331
                blocks.append(block)
332
        if hasattr(authenticator, 'is_hidden'):
333
            blocks[-1]['is_hidden'] = authenticator.is_hidden(request)
334
        else:
335
            blocks[-1]['is_hidden'] = False
338
            for block in auth_blocks:
339
                if block:
340
                    if block['status_code'] != 200:
341
                        return block['response']
342
                    block['is_hidden'] = False
343
                    blocks.append(block)
344
        # TODO: remove 'is_hidden' below after cleaning up the templates
345
        blocks[-1]['is_hidden'] = False
336 346

  
337 347
    # Old frontends API
338 348
    for block in blocks:
src/authentic2_auth_oidc/authenticators.py
18 18
from django.shortcuts import render
19 19

  
20 20
from . import app_settings, utils
21
from authentic2.utils import make_url
21 22

  
22 23

  
23 24
class OIDCAuthenticator(object):
......
30 31
    def id(self):
31 32
        return 'oidc'
32 33

  
34
    @property
35
    def instances(self):
36
        for p in utils.get_providers(shown=True):
37
            yield (p.slug, p)
38

  
33 39
    def login(self, request, *args, **kwargs):
34 40
        context = kwargs.get('context', {})
35
        context['providers'] = utils.get_providers(shown=True)
36
        return render(request, 'authentic2_auth_oidc/login.html', context)
41
        if kwargs.get('instance'):
42
            instance = kwargs['instance']
43
            context['provider'] = instance
44
            context['login_url'] = make_url('oidc-login', kwargs={'pk': instance.id},
45
                                            request=request, keep_params=True)
46
            return render(request, 'authentic2_auth_oidc/login.html', context)
src/authentic2_auth_oidc/templates/authentic2_auth_oidc/login.html
1
{% for provider in providers %}
2
  <p id="oidc-p-{% firstof provider.slug provider.name|slugify %}">
3
    <a id="oidc-a-{% firstof provider.slug  provider.name|slugify %}"
4
       href="{% url "oidc-login" pk=provider.pk %}?{{ request.GET.urlencode }}">{{ provider.name }}</a>
5
  </p>
6
{% endfor %}
1
<p id="oidc-p-{% firstof provider.slug provider.name|slugify %}">
2
  <a id="oidc-a-{% firstof provider.slug  provider.name|slugify %}"
3
     href="{{ login_url }}">{{ provider.name }}</a>
4
</p>
tests/test_auth_oidc.py
283 283
    return qs
284 284

  
285 285

  
286
def test_providers_on_login_page(oidc_provider, app):
287
    response = app.get('/login/')
288
    # two frontends should be present on login page
289
    assert response.pyquery('p#oidc-p-oididp')
290
    provider = OIDCProvider.objects.create(
291
        ou=get_default_ou(),
292
        name='OIDCIDP 2',
293
        slug='oidcidp-2',
294
        issuer='https://idp2.example.com/',
295
        authorization_endpoint='https://idp2.example.com/authorize',
296
        token_endpoint='https://idp2.example.com/token',
297
        end_session_endpoint='https://idp2.example.com/logout',
298
        userinfo_endpoint='https://idp*é.example.com/user_info',
299
        token_revocation_endpoint='https://idp2.example.com/revoke',
300
        max_auth_age=10,
301
        strategy=OIDCProvider.STRATEGY_CREATE,
302
        jwkset_json=None,
303
        idtoken_algo=OIDCProvider.ALGO_RSA,
304
        claims_parameter_supported=False
305
    )
306

  
307
    response = app.get('/login/?next=http://example.com')
308
    assert response.pyquery('a#oidc-a-oididp')
309
    assert response.pyquery('a#oidc-a-oidcidp-2')
310
    assert '?next=' in response.pyquery('a#oidc-a-oididp').attr('href')
311
    assert '?next=' in response.pyquery('a#oidc-a-oidcidp-2').attr('href')
312
    provider.delete()
313

  
314

  
286 315
def test_sso(app, caplog, code, oidc_provider, oidc_provider_jwkset, login_url, login_callback_url, hooks):
287 316
    OU = get_ou_model()
288 317
    cassis = OU.objects.create(name='Cassis', slug='cassis')
289
-