Projet

Général

Profil

0005-models-mind-auth-level-at-service-access-authorizati.patch

Valentin Deniaud, 21 juin 2019 14:19

Télécharger (8,92 ko)

Voir les différences:

Subject: [PATCH] models: mind auth level at service access authorization

Allows to enable multi-factor authentication on a per-service basis via
service access restriction to some roles.
 src/authentic2/idp/saml/saml2_endpoints.py |  2 +-
 src/authentic2/manager/role_views.py       |  8 ++++----
 src/authentic2/manager/utils.py            |  5 -----
 src/authentic2/manager/views.py            |  4 ++--
 src/authentic2/middleware.py               |  2 ++
 src/authentic2/models.py                   | 15 +++++++++++----
 src/authentic2/utils.py                    |  9 +++++++++
 src/authentic2_idp_cas/views.py            |  2 +-
 src/authentic2_idp_oidc/views.py           |  2 +-
 9 files changed, 31 insertions(+), 18 deletions(-)
src/authentic2/idp/saml/saml2_endpoints.py
694 694
        set_saml2_response_responder_status_code(login.response, lasso.SAML2_STATUS_CODE_NO_PASSIVE)
695 695
        return finish_sso(request, login)
696 696

  
697
    service.authorize(request.user)
697
    service.authorize(request)
698 698

  
699 699
    hooks.call_hooks('event', name='sso-request', idp='saml2', service=service)
700 700

  
src/authentic2/manager/role_views.py
30 30
from django_rbac.exceptions import InsufficientAuthLevel
31 31
from django_rbac.utils import get_role_model, get_permission_model, get_ou_model
32 32

  
33
from authentic2.utils import redirect
33
from authentic2.utils import redirect, increase_auth_level
34 34
from authentic2 import hooks, data_transfer
35 35

  
36 36
from . import tables, views, resources, forms, app_settings, utils
......
178 178
                                     user=self.request.user, role=self.object, member=user)
179 179
        else:
180 180
            if self.could_change:
181
                return utils.increase_auth_level(self.request)
181
                return increase_auth_level(self.request)
182 182
            messages.warning(self.request, _('You are not authorized'))
183 183
        return super(RoleMembersView, self).form_valid(form)
184 184

  
......
209 209
    def post(self, request, *args, **kwargs):
210 210
        if not self.can_delete:
211 211
            if self.could_delete:
212
                return utils.increase_auth_level(self.request)
212
                return increase_auth_level(self.request)
213 213
            raise PermissionDenied
214 214
        return super(RoleDeleteView, self).post(request, *args, **kwargs)
215 215

  
......
265 265
                                         user=self.request.user, role=self.object, permission=perm)
266 266
        else:
267 267
            if self.could_change:
268
                return utils.increase_auth_level(self.request)
268
                return increase_auth_level(self.request)
269 269
            messages.warning(self.request, _('You are not authorized'))
270 270
        return super(RolePermissionsView, self).form_valid(form)
271 271

  
src/authentic2/manager/utils.py
41 41
@GlobalCache(timeout=10)
42 42
def get_ou_count():
43 43
    return get_ou_model().objects.count()
44

  
45

  
46
def increase_auth_level(request):
47
    current_auth_level = request.session.get('auth_level', 1)
48
    return login_require(request, params={'auth_level': current_auth_level + 1})
src/authentic2/manager/views.py
43 43

  
44 44
from authentic2.data_transfer import export_site, import_site, DataImportError, ImportContext
45 45
from authentic2.forms.profile import modelform_factory
46
from authentic2.utils import redirect, batch_queryset
46
from authentic2.utils import redirect, batch_queryset, increase_auth_level
47 47
from authentic2.decorators import json as json_view
48 48
from authentic2 import hooks
49 49

  
......
150 150
        try:
151 151
            response = self.authorize(request, *args, **kwargs)
152 152
        except InsufficientAuthLevel:
153
            return utils.increase_auth_level(request)
153
            return increase_auth_level(request)
154 154
        if response is not None:
155 155
            return response
156 156
        return super(PermissionMixin, self).dispatch(request, *args, **kwargs)
src/authentic2/middleware.py
265 265
    def process_exception(self, request, exception):
266 266
        if not isinstance(exception, (utils.ServiceAccessDenied,)):
267 267
            return None
268
        if isinstance(exception, (utils.IncreaseAuthLevel,)):
269
            return utils.increase_auth_level(request)
268 270
        return utils.unauthorized_view(request, exception.service)
src/authentic2/models.py
39 39
from . import managers
40 40
# install our natural_key implementation
41 41
from . import natural_key as unused_natural_key  # noqa: F401
42
from .utils import ServiceAccessDenied
42
from .utils import ServiceAccessDenied, IncreaseAuthLevel
43 43

  
44 44

  
45 45
class DeletedUser(models.Model):
......
369 369
    def __repr__(self):
370 370
        return '<%s %r>' % (self.__class__.__name__, six.text_type(self))
371 371

  
372
    def authorize(self, user):
372
    def authorize(self, request):
373 373
        if not self.authorized_roles.exists():
374 374
            return True
375
        if user.roles_and_parents().filter(allowed_services=self).exists():
376
            return True
375
        allowed_roles = request.user.roles_and_parents() \
376
            .filter(allowed_services=self) \
377
            .set_needed_auth_levels(request.user)
378
        user_auth_level = request.session.get('auth_level', 1)
379
        for role in allowed_roles:
380
            if role.needed_auth_level <= user_auth_level:
381
                return True
382
        if allowed_roles:
383
            raise IncreaseAuthLevel(service=self)
377 384
        raise ServiceAccessDenied(service=self)
378 385

  
379 386
    def add_authorized_role(self, role):
src/authentic2/utils.py
977 977
        self.service = service
978 978

  
979 979

  
980
class IncreaseAuthLevel(ServiceAccessDenied):
981
    pass
982

  
983

  
980 984
def unauthorized_view(request, service):
981 985
    context = {'callback_url': service.unauthorized_url or reverse('auth_homepage')}
982 986
    return render(request, 'authentic2/unauthorized.html', context=context)
......
1157 1161
    if session is not None:
1158 1162
        return session.get(constants.AUTHENTICATION_EVENTS_SESSION_KEY, [])
1159 1163
    return []
1164

  
1165

  
1166
def increase_auth_level(request):
1167
    current_auth_level = request.session.get('auth_level', 1)
1168
    return login_require(request, params={'auth_level': current_auth_level + 1})
src/authentic2_idp_cas/views.py
181 181
            return self.authenticate(request, st)
182 182
        # if user not authorized, a ServiceAccessDenied exception
183 183
        # is raised and handled by ServiceAccessMiddleware
184
        st.service.authorize(request.user)
184
        st.service.authorize(request)
185 185

  
186 186
        self.validate_ticket(request, st)
187 187
        if st.valid():
src/authentic2_idp_oidc/views.py
202 202

  
203 203
    # if user not authorized, a ServiceAccessDenied exception
204 204
    # is raised and handled by ServiceAccessMiddleware
205
    client.authorize(request.user)
205
    client.authorize(request)
206 206

  
207 207
    last_auth = last_authentication_event(request=request)
208 208
    if max_age is not None and time.time() - last_auth['when'] >= max_age:
209
-