misc: use one-time tokens instead of cache (#39745)
This commit is contained in:
parent
3d55b1a0c5
commit
4e35e3b572
|
@ -281,7 +281,7 @@ class UserDetailView(OtherActionsMixin, BaseDetailView):
|
|||
|
||||
def action_su(self, request, *args, **kwargs):
|
||||
return redirect(request, 'auth_logout',
|
||||
params={REDIRECT_FIELD_NAME: build_su_url(self.object)})
|
||||
params={REDIRECT_FIELD_NAME: switch_user.build_url(self.object)})
|
||||
|
||||
# Copied from PasswordResetForm implementation
|
||||
def send_mail(self, subject_template_name, email_template_name,
|
||||
|
@ -821,7 +821,7 @@ class UserSuView(MediaMixin, TitleMixin, PermissionMixin, DetailView):
|
|||
ctx['su_url'] = make_url(
|
||||
'auth_logout',
|
||||
|
||||
params={REDIRECT_FIELD_NAME: build_su_url(self.object, self.duration)},
|
||||
params={REDIRECT_FIELD_NAME: switch_user.build_url(self.object, self.duration)},
|
||||
request=self.request,
|
||||
absolute=True)
|
||||
ctx['duration'] = self.duration
|
||||
|
|
|
@ -111,7 +111,7 @@ urlpatterns = [
|
|||
url(r'^$', views.homepage, name='auth_homepage'),
|
||||
url(r'^login/$', views.login, name='auth_login'),
|
||||
url(r'^logout/$', views.logout, name='auth_logout'),
|
||||
url(r'^su/(?P<token>[a-f0-9]+)/$', views.su, name='su'),
|
||||
url(r'^su/(?P<uuid>[A-Za-z0-9_-]+)/$', views.su, name='su'),
|
||||
url(r'^accounts/', include(accounts_urlpatterns)),
|
||||
url(r'^admin/', include(admin.site.urls)),
|
||||
url(r'^idp/', include('authentic2.idp.urls')),
|
||||
|
|
|
@ -867,34 +867,6 @@ def to_dict_of_set(d):
|
|||
return dict((k, set(v)) for k, v in d.items())
|
||||
|
||||
|
||||
def build_su_url(user, duration=30):
|
||||
token = get_hex_uuid()
|
||||
data = {'user_pk': user.pk}
|
||||
cache.set('switch-%s' % token, data, duration)
|
||||
return make_url('su', kwargs={'token': token})
|
||||
|
||||
HEX_RE = re.compile('^[a-f0-9]+$')
|
||||
|
||||
|
||||
def get_su_user(token):
|
||||
User = get_user_model()
|
||||
if not token:
|
||||
return None
|
||||
if not HEX_RE.match(token):
|
||||
return None
|
||||
key = 'switch-%s' % token
|
||||
data = cache.get(key)
|
||||
if not isinstance(data, dict):
|
||||
return None
|
||||
if not data.get('user_pk'):
|
||||
return None
|
||||
cache.delete(key)
|
||||
try:
|
||||
return User.objects.get(pk=data['user_pk'])
|
||||
except User.DoesNotExist:
|
||||
return None
|
||||
|
||||
|
||||
def datetime_to_utc(dt):
|
||||
if timezone.is_naive(dt):
|
||||
dt = timezone.make_aware(dt, timezone.get_current_timezone())
|
||||
|
|
|
@ -0,0 +1,39 @@
|
|||
# authentic2 - versatile identity manager
|
||||
# Copyright (C) 2010-2020 Entr'ouvert
|
||||
#
|
||||
# This program is free software: you can redistribute it and/or modify it
|
||||
# under the terms of the GNU Affero General Public License as published
|
||||
# by the Free Software Foundation, either version 3 of the License, or
|
||||
# (at your option) any later version.
|
||||
#
|
||||
# This program is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU Affero General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU Affero General Public License
|
||||
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
from authentic2.models import Token
|
||||
from authentic2.custom_user.models import User
|
||||
|
||||
from authentic2.utils import make_url
|
||||
|
||||
|
||||
def build_url(user, duration=30):
|
||||
token = Token.create('su', {'user_pk': user.pk}, duration=duration)
|
||||
return make_url('su', kwargs={'uuid': token.uuid_b64url})
|
||||
|
||||
|
||||
def resolve_token(uuid):
|
||||
try:
|
||||
token = Token.use('su', uuid)
|
||||
except (ValueError, TypeError, Token.DoesNotExist):
|
||||
return None
|
||||
|
||||
try:
|
||||
return User.objects.get(pk=token.content['user_pk'])
|
||||
except User.DoesNotExist:
|
||||
return None
|
||||
|
||||
|
|
@ -54,6 +54,7 @@ from django.template import loader
|
|||
|
||||
from . import (utils, app_settings, compat, decorators, constants,
|
||||
models, cbv, hooks, validators)
|
||||
from .utils import switch_user
|
||||
from .a2_rbac.utils import get_default_ou
|
||||
from .a2_rbac.models import OrganizationalUnit as OU
|
||||
from .forms import (
|
||||
|
@ -1210,8 +1211,8 @@ def notimplemented_view(request):
|
|||
|
||||
|
||||
class SuView(View):
|
||||
def get(self, request, token):
|
||||
user = utils.get_su_user(token)
|
||||
def get(self, request, uuid):
|
||||
user = switch_user.resolve_token(uuid)
|
||||
if not user:
|
||||
raise Http404
|
||||
return utils.simulate_authentication(request, user, 'su')
|
||||
|
|
Loading…
Reference in New Issue