0001-auth-separate-OIDC-providers-in-blocks-on-login-page.patch
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'] = 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 |
blocks.append(block) |
|
343 |
if hasattr(authenticator, 'is_hidden'): |
|
344 |
blocks[-1]['is_hidden'] = authenticator.is_hidden(request) |
|
345 |
else: |
|
346 |
blocks[-1]['is_hidden'] = False |
|
336 | 347 | |
337 | 348 |
# Old frontends API |
338 | 349 |
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 |
- |