auth: separate OIDC providers in blocks on login page (#31259)

This commit is contained in:
Serghei Mihai 2019-03-08 14:57:45 +01:00
parent 0fc5a97113
commit 216323c7ad
4 changed files with 59 additions and 17 deletions

View File

@ -320,19 +320,29 @@ def login(request, template_name='authentic2/login.html',
block['form'] = form_class()
blocks.append(block)
else: # New frontends API
auth_blocks = []
parameters = {'request': request,
'context': context}
block = utils.get_authenticator_method(authenticator, 'login', parameters)
# check if the authenticator has multiple instances
if hasattr(authenticator, 'instances'):
for instance_id, instance in authenticator.instances(**parameters):
parameters['instance'] = instance
block = utils.get_authenticator_method(authenticator, 'login', parameters)
# update block id in order to separate instances
block['id'] = '%s_%s' % (block['id'], instance_id)
auth_blocks.append(block)
else:
auth_blocks.append(utils.get_authenticator_method(authenticator, 'login', parameters))
# If a login frontend method returns an HttpResponse with a status code != 200
# this response is returned.
if block:
if block['status_code'] != 200:
return block['response']
blocks.append(block)
if hasattr(authenticator, 'is_hidden'):
blocks[-1]['is_hidden'] = authenticator.is_hidden(request)
else:
blocks[-1]['is_hidden'] = False
for block in auth_blocks:
if block:
if block['status_code'] != 200:
return block['response']
block['is_hidden'] = False
blocks.append(block)
# TODO: remove attribute below after cleaning up the templates
blocks[-1]['is_hidden'] = False
# Old frontends API
for block in blocks:

View File

@ -30,7 +30,12 @@ class OIDCAuthenticator(object):
def id(self):
return 'oidc'
def instances(self, request, *args, **kwargs):
for p in utils.get_providers(shown=True):
yield (p.slug, p)
def login(self, request, *args, **kwargs):
context = kwargs.get('context', {})
context['providers'] = utils.get_providers(shown=True)
return render(request, 'authentic2_auth_oidc/login.html', context)
if kwargs.get('instance'):
context['provider'] = kwargs['instance']
return render(request, 'authentic2_auth_oidc/login.html', context)

View File

@ -1,6 +1,4 @@
{% for provider in providers %}
<p id="oidc-p-{% firstof provider.slug provider.name|slugify %}">
<a id="oidc-a-{% firstof provider.slug provider.name|slugify %}"
href="{% url "oidc-login" pk=provider.pk %}?{{ request.GET.urlencode }}">{{ provider.name }}</a>
</p>
{% endfor %}
<p id="oidc-p-{% firstof provider.slug provider.name|slugify %}">
<a id="oidc-a-{% firstof provider.slug provider.name|slugify %}"
href="{% url "oidc-login" pk=provider.pk %}?{{ request.GET.urlencode }}">{{ provider.name }}</a>
</p>

View File

@ -304,6 +304,35 @@ def check_simple_qs(qs):
return qs
def test_providers_on_login_page(oidc_provider, app):
response = app.get('/login/')
# two frontends should be present on login page
assert response.pyquery('p#oidc-p-oididp')
OIDCProvider.objects.create(
id=2,
ou=get_default_ou(),
name='OIDCIDP 2',
slug='oidcidp-2',
issuer='https://idp2.example.com/',
authorization_endpoint='https://idp2.example.com/authorize',
token_endpoint='https://idp2.example.com/token',
end_session_endpoint='https://idp2.example.com/logout',
userinfo_endpoint='https://idp*é.example.com/user_info',
token_revocation_endpoint='https://idp2.example.com/revoke',
max_auth_age=10,
strategy=OIDCProvider.STRATEGY_CREATE,
jwkset_json=None,
idtoken_algo=OIDCProvider.ALGO_RSA,
claims_parameter_supported=False
)
response = app.get('/login/')
assert response.pyquery('p#oidc-p-oididp')
assert response.pyquery('p#oidc-p-oidcidp-2')
def test_sso(app, caplog, code, oidc_provider, oidc_provider_jwkset, login_url, login_callback_url, hooks):
OU = get_ou_model()
cassis = OU.objects.create(name='Cassis', slug='cassis')