0002-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 | ||
---|---|---|
30 | 30 |
def id(self): |
31 | 31 |
return 'oidc' |
32 | 32 | |
33 |
@property |
|
34 |
def instances(self): |
|
35 |
for p in utils.get_providers(shown=True): |
|
36 |
yield (p.slug, p) |
|
37 | ||
33 | 38 |
def login(self, request, *args, **kwargs): |
34 | 39 |
context = kwargs.get('context', {}) |
35 |
context['providers'] = utils.get_providers(shown=True) |
|
36 |
return render(request, 'authentic2_auth_oidc/login.html', context) |
|
40 |
if kwargs.get('instance'): |
|
41 |
context['provider'] = kwargs['instance'] |
|
42 |
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.next|urlencode }}">{{ provider.name }}</a> |
|
5 |
</p> |
|
6 |
{% endfor %} |
|
7 | ||
1 |
<p id="oidc-p-{% firstof provider.slug provider.name|slugify %}"> |
|
2 |
<a id="oidc-a-{% firstof provider.slug provider.name|slugify %}" |
|
3 |
href="{% url "oidc-login" pk=provider.pk %}?{{ request.GET.next|urlencode }}">{{ 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 |
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/') |
|
308 |
assert response.pyquery('p#oidc-p-oididp') |
|
309 |
assert response.pyquery('p#oidc-p-oidcidp-2') |
|
310 | ||
311 | ||
312 | ||
313 | ||
286 | 314 |
def test_sso(app, caplog, code, oidc_provider, oidc_provider_jwkset, login_url, login_callback_url, hooks): |
287 | 315 |
OU = get_ou_model() |
288 | 316 |
cassis = OU.objects.create(name='Cassis', slug='cassis') |
289 |
- |