Replace the certificate field by an authentication_level field (fixes #7653)
The field cannot be empty. On each sso it's matched agains the authentication levels found in the session.
This commit is contained in:
parent
40b1b6d5f2
commit
3cac2e4402
|
@ -1,4 +1,10 @@
|
|||
from django.utils.translation import ugettext_lazy as _
|
||||
|
||||
AUTHENTICATION_LEVELS = (
|
||||
('password-on-https', _('login/password')),
|
||||
('ssl-collectivity', _('collectivity certificate + login/password')),
|
||||
('ssl', _('X509 RGS certificate')),
|
||||
)
|
||||
PRATIC_AUTOLOGIN_COOKIE_NAME = 'pratic-autologin'
|
||||
PRATIC_AUTOLOGIN_COOKIE_MAX_AGE = 60*10 # 10 minutes
|
||||
PRATIC_AUTHN_CONTEXT_SSL_COLLECTIVITY = 'urn:cdg59.fr:names:tc:SAML:2.0:ac:classes:X509Collectivity'
|
||||
|
|
|
@ -0,0 +1,25 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
from __future__ import unicode_literals
|
||||
|
||||
from django.db import models, migrations
|
||||
import authentic2.saml.fields
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('authentic2_pratic', '0006_auto_20150622_1600'),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.RemoveField(
|
||||
model_name='serviceinstance',
|
||||
name='certificate',
|
||||
),
|
||||
migrations.AddField(
|
||||
model_name='serviceinstance',
|
||||
name='authentication_level',
|
||||
field=authentic2.saml.fields.MultiSelectField(default='password-on-https,ssl-collectivity,ssl', max_length=256, verbose_name='authentification level', choices=[(b'password-on-https', 'login/password'), (b'ssl-collectivity', 'collectivity certificate + login/password'), (b'ssl', 'X509 RGS certificate')]),
|
||||
preserve_default=True,
|
||||
),
|
||||
]
|
|
@ -15,6 +15,9 @@ from authentic2.idp.signals import authorize_service
|
|||
from authentic2.custom_user.models import User as BaseUser
|
||||
from authentic2.a2_rbac.models import OrganizationalUnit
|
||||
from authentic2.constants import AUTHENTICATION_EVENTS_SESSION_KEY
|
||||
from authentic2.saml.fields import MultiSelectField
|
||||
|
||||
from . import constants
|
||||
|
||||
|
||||
class User(BaseUser):
|
||||
|
@ -341,10 +344,12 @@ class ServiceInstance(Model):
|
|||
cas_service_url = URLField(
|
||||
verbose_name=_('CAS service URL'),
|
||||
blank=True)
|
||||
certificate = BooleanField(
|
||||
verbose_name=_('Authentication by certificate only'),
|
||||
default=False,
|
||||
blank=True)
|
||||
authentication_level = MultiSelectField(
|
||||
verbose_name=_('authentification level'),
|
||||
max_length=256,
|
||||
blank=False,
|
||||
default='password-on-https,ssl-collectivity,ssl',
|
||||
choices=constants.AUTHENTICATION_LEVELS)
|
||||
a2_service = ForeignKey(
|
||||
to='authentic2.Service',
|
||||
verbose_name=_('related authentic2 service'),
|
||||
|
@ -445,10 +450,9 @@ def authorize_service_cb(request, user, audience, attributes, **kwargs):
|
|||
logger.warn('unable to find service for audience %r and user %r in collectivity %r',
|
||||
audience, unicode(user), unicode(collectivity))
|
||||
return authz(False, _('This service is unknown.'))
|
||||
if si.certificate:
|
||||
events = request.session.get(AUTHENTICATION_EVENTS_SESSION_KEY, [])
|
||||
if not any(event['how'] in ('ssl', 'ssl-collectivity') for event in events):
|
||||
return authz(False, _('This service requires certificate authentication.'))
|
||||
events = request.session.get(AUTHENTICATION_EVENTS_SESSION_KEY, [])
|
||||
if not any(event['how'] in si.authentication_level):
|
||||
return authz(False, _('This service requires certificate authentication.'))
|
||||
|
||||
if Access.objects.filter(service_instance=si, user=user).exists():
|
||||
logger.info('%r of collectivity %r is authorized to connect on %r', unicode(user),
|
||||
|
|
|
@ -13,11 +13,17 @@
|
|||
{% block content %}
|
||||
<h2 id="services-header">Services</h2>
|
||||
<ul>
|
||||
{% for name, url, slug in service_links %}
|
||||
{% for name, url, slug, needed_authent in service_links %}
|
||||
<li>
|
||||
<a id="service-link-{{ slug }}" href="{{ url }}">
|
||||
{{ name }}
|
||||
</a>
|
||||
{% if needed_authent %}
|
||||
<a id="service-link-{{ slug }}">
|
||||
{{ name }}
|
||||
</a> (niveau d'authentification insuffisant: {{ needed_authent }})
|
||||
{% else %}
|
||||
<a id="service-link-{{ slug }}" href="{{ url }}">
|
||||
{{ name }}
|
||||
</a>
|
||||
{% endif %}
|
||||
</li>
|
||||
{% endfor %}
|
||||
</ul>
|
||||
|
|
|
@ -11,12 +11,12 @@ from django.views.generic import (TemplateView, UpdateView,
|
|||
CreateView, DeleteView)
|
||||
from django_tables2 import SingleTableView
|
||||
|
||||
from authentic2.constants import AUTHENTICATION_EVENTS_SESSION_KEY
|
||||
from authentic2.manager.views import AjaxFormViewMixin, \
|
||||
ActionMixin, OtherActionsMixin, TitleMixin, Action
|
||||
|
||||
from authentic2.manager.user_views import UserEditView, UserAddView
|
||||
|
||||
from . import models, tables, forms
|
||||
from . import models, tables, forms, constants
|
||||
|
||||
class SearchMixin(object):
|
||||
search_filter = []
|
||||
|
@ -365,20 +365,36 @@ service_instance_delete = ServiceInstanceDeleteView.as_view()
|
|||
# accesses
|
||||
collectivity_accesses = AccessesView.as_view()
|
||||
|
||||
|
||||
def get_service_links(request):
|
||||
events = request.session.get(AUTHENTICATION_EVENTS_SESSION_KEY, [])
|
||||
authentication_levels = set(event['how'] for event in events)
|
||||
|
||||
if not hasattr(request.user, 'collectivity'):
|
||||
return []
|
||||
service_links = []
|
||||
qs = request.user.collectivity.service_instances.select_related()
|
||||
qs = qs.filter(access__user=request.user)
|
||||
for service_instance in qs:
|
||||
needed_authent = ''
|
||||
levels = dict(constants.AUTHENTICATION_LEVELS)
|
||||
if not bool(set(service_instance.authentication_level) & authentication_levels):
|
||||
needed_authent0 = service_instance.authentication_level
|
||||
needed_authent1 = [levels[level] for level in needed_authent0]
|
||||
needed_authent2 = map(unicode, needed_authent1)
|
||||
needed_authent = u', '.join(needed_authent2)
|
||||
if service_instance.service.is_global:
|
||||
name = service_instance.service.name
|
||||
slug = service_instance.service.slug
|
||||
url = service_instance.service.service_url
|
||||
else:
|
||||
name = service_instance.service.name
|
||||
slug = service_instance.slug
|
||||
url = service_instance.service_url
|
||||
service_links.append((name, url, slug, needed_authent))
|
||||
return service_links
|
||||
|
||||
@login_required
|
||||
def agent_homepage(request):
|
||||
ctx = {}
|
||||
if hasattr(request.user, 'collectivity'):
|
||||
service_links = ctx['service_links'] = []
|
||||
qs = request.user.collectivity.service_instances.select_related()
|
||||
for service_instance in qs:
|
||||
if service_instance.service.is_global:
|
||||
name = service_instance.service.name
|
||||
slug = service_instance.service.slug
|
||||
url = service_instance.service.service_url
|
||||
else:
|
||||
name = service_instance.service.name
|
||||
slug = service_instance.slug
|
||||
url = service_instance.service_url
|
||||
service_links.append((name, url, slug))
|
||||
ctx = {'service_links': get_service_links(request)}
|
||||
return render(request, 'authentic2_pratic/agent_homepage.html', ctx)
|
||||
|
|
Reference in New Issue