Projet

Général

Profil

0003-misc-use-one-time-tokens-instead-of-cache-39745.patch

Benjamin Dauvergne, 11 février 2020 14:54

Télécharger (5,76 ko)

Voir les différences:

Subject: [PATCH 3/3] misc: use one-time tokens instead of cache (#39745)

 src/authentic2/manager/user_views.py |  4 +--
 src/authentic2/urls.py               |  2 +-
 src/authentic2/utils/__init__.py     | 28 --------------------
 src/authentic2/utils/switch_user.py  | 39 ++++++++++++++++++++++++++++
 src/authentic2/views.py              |  5 ++--
 5 files changed, 45 insertions(+), 33 deletions(-)
 create mode 100644 src/authentic2/utils/switch_user.py
src/authentic2/manager/user_views.py
281 281

  
282 282
    def action_su(self, request, *args, **kwargs):
283 283
        return redirect(request, 'auth_logout',
284
                        params={REDIRECT_FIELD_NAME: build_su_url(self.object)})
284
                        params={REDIRECT_FIELD_NAME: switch_user.build_url(self.object)})
285 285

  
286 286
    # Copied from PasswordResetForm implementation
287 287
    def send_mail(self, subject_template_name, email_template_name,
......
821 821
        ctx['su_url'] = make_url(
822 822
            'auth_logout',
823 823

  
824
            params={REDIRECT_FIELD_NAME: build_su_url(self.object, self.duration)},
824
            params={REDIRECT_FIELD_NAME: switch_user.build_url(self.object, self.duration)},
825 825
            request=self.request,
826 826
            absolute=True)
827 827
        ctx['duration'] = self.duration
src/authentic2/urls.py
111 111
    url(r'^$', views.homepage, name='auth_homepage'),
112 112
    url(r'^login/$', views.login, name='auth_login'),
113 113
    url(r'^logout/$', views.logout, name='auth_logout'),
114
    url(r'^su/(?P<token>[a-f0-9]+)/$', views.su, name='su'),
114
    url(r'^su/(?P<uuid>[A-Za-z0-9_-]+)/$', views.su, name='su'),
115 115
    url(r'^accounts/', include(accounts_urlpatterns)),
116 116
    url(r'^admin/', include(admin.site.urls)),
117 117
    url(r'^idp/', include('authentic2.idp.urls')),
src/authentic2/utils/__init__.py
867 867
    return dict((k, set(v)) for k, v in d.items())
868 868

  
869 869

  
870
def build_su_url(user, duration=30):
871
    token = get_hex_uuid()
872
    data = {'user_pk': user.pk}
873
    cache.set('switch-%s' % token, data, duration)
874
    return make_url('su', kwargs={'token': token})
875

  
876
HEX_RE = re.compile('^[a-f0-9]+$')
877

  
878

  
879
def get_su_user(token):
880
    User = get_user_model()
881
    if not token:
882
        return None
883
    if not HEX_RE.match(token):
884
        return None
885
    key = 'switch-%s' % token
886
    data = cache.get(key)
887
    if not isinstance(data, dict):
888
        return None
889
    if not data.get('user_pk'):
890
        return None
891
    cache.delete(key)
892
    try:
893
        return User.objects.get(pk=data['user_pk'])
894
    except User.DoesNotExist:
895
        return None
896

  
897

  
898 870
def datetime_to_utc(dt):
899 871
    if timezone.is_naive(dt):
900 872
        dt = timezone.make_aware(dt, timezone.get_current_timezone())
src/authentic2/utils/switch_user.py
1
# authentic2 - versatile identity manager
2
# Copyright (C) 2010-2020 Entr'ouvert
3
#
4
# This program is free software: you can redistribute it and/or modify it
5
# under the terms of the GNU Affero General Public License as published
6
# by the Free Software Foundation, either version 3 of the License, or
7
# (at your option) any later version.
8
#
9
# This program is distributed in the hope that it will be useful,
10
# but WITHOUT ANY WARRANTY; without even the implied warranty of
11
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12
# GNU Affero General Public License for more details.
13
#
14
# You should have received a copy of the GNU Affero General Public License
15
# along with this program.  If not, see <http://www.gnu.org/licenses/>.
16

  
17
from authentic2.models import Token
18
from authentic2.custom_user.models import User
19

  
20
from authentic2.utils import make_url
21

  
22

  
23
def build_url(user, duration=30):
24
    token = Token.create('su', {'user_pk': user.pk}, expires=duration)
25
    return make_url('su', kwargs={'uuid': token.uuid_b64url})
26

  
27

  
28
def resolve_token(uuid):
29
    try:
30
        token = Token.use('su', uuid)
31
    except (ValueError, TypeError, Token.DoesNotExist):
32
        return None
33

  
34
    try:
35
        return User.objects.get(pk=token.content['user_pk'])
36
    except User.DoesNotExist:
37
        return None
38

  
39

  
src/authentic2/views.py
54 54

  
55 55
from . import (utils, app_settings, compat, decorators, constants,
56 56
               models, cbv, hooks, validators)
57
from .utils import switch_user
57 58
from .a2_rbac.utils import get_default_ou
58 59
from .a2_rbac.models import OrganizationalUnit as OU
59 60
from .forms import (
......
1210 1211

  
1211 1212

  
1212 1213
class SuView(View):
1213
    def get(self, request, token):
1214
        user = utils.get_su_user(token)
1214
    def get(self, request, uuid):
1215
        user = switch_user.resolve_token(uuid)
1215 1216
        if not user:
1216 1217
            raise Http404
1217 1218
        return utils.simulate_authentication(request, user, 'su')
1218
-