Log out other sessions after email or 2FA changes

This commit is contained in:
Raphael Michel
2020-03-22 10:51:00 +01:00
parent 25b80cbb57
commit 027a785ab5
3 changed files with 52 additions and 1 deletions

View File

@@ -0,0 +1,20 @@
# Generated by Django 2.2.9 on 2020-03-21 15:12
from django.db import migrations, models
import pretix.base.models.auth
class Migration(migrations.Migration):
dependencies = [
('pretixbase', '0146_giftcardtransaction_text'),
]
operations = [
migrations.AddField(
model_name='user',
name='session_token',
field=models.CharField(default=pretix.base.models.auth.generate_session_token, max_length=32),
),
]

View File

@@ -12,7 +12,7 @@ from django.contrib.auth.tokens import default_token_generator
from django.contrib.contenttypes.models import ContentType
from django.db import models
from django.db.models import Q
from django.utils.crypto import get_random_string
from django.utils.crypto import get_random_string, salted_hmac
from django.utils.timezone import now
from django.utils.translation import ugettext_lazy as _
from django_otp.models import Device
@@ -54,6 +54,10 @@ def generate_notifications_token():
return get_random_string(length=32)
def generate_session_token():
return get_random_string(length=32)
class SuperuserPermissionSet:
def __contains__(self, item):
return True
@@ -110,6 +114,7 @@ class User(AbstractBaseUser, PermissionsMixin, LoggingMixin):
)
notifications_token = models.CharField(max_length=255, default=generate_notifications_token)
auth_backend = models.CharField(max_length=255, default='native')
session_token = models.CharField(max_length=32, default=generate_session_token)
objects = UserManager()
@@ -382,6 +387,20 @@ class User(AbstractBaseUser, PermissionsMixin, LoggingMixin):
self._staff_session_cache[session_key] = sess
return self._staff_session_cache[session_key]
def get_session_auth_hash(self):
"""
Return an HMAC that needs to
"""
key_salt = "pretix.base.models.User.get_session_auth_hash"
payload = self.password
payload += self.email
payload += self.session_token
return salted_hmac(key_salt, payload).hexdigest()
def update_session_token(self):
self.session_token = generate_session_token()
self.save(update_fields=['session_token'])
class StaffSession(models.Model):
user = models.ForeignKey('User', on_delete=models.PROTECT)

View File

@@ -323,6 +323,8 @@ class User2FADeviceDeleteView(RecentAuthenticationRequiredMixin, TemplateView):
msgs.append(_('Two-factor authentication has been disabled.'))
self.request.user.send_security_notice(msgs)
self.request.user.update_session_token()
update_session_auth_hash(self.request, self.request.user)
messages.success(request, _('The device has been removed.'))
return redirect(reverse('control:user.settings.2fa'))
@@ -434,6 +436,8 @@ class User2FADeviceConfirmWebAuthnView(RecentAuthenticationRequiredMixin, Templa
_('Two-factor authentication has been enabled.')
)
self.request.user.send_security_notice(notices)
self.request.user.update_session_token()
update_session_auth_hash(self.request, self.request.user)
note = ''
if not self.request.user.require_2fa:
@@ -492,6 +496,8 @@ class User2FADeviceConfirmTOTPView(RecentAuthenticationRequiredMixin, TemplateVi
_('Two-factor authentication has been enabled.')
)
self.request.user.send_security_notice(notices)
self.request.user.update_session_token()
update_session_auth_hash(self.request, self.request.user)
note = ''
if not self.request.user.require_2fa:
@@ -526,6 +532,8 @@ class User2FAEnableView(RecentAuthenticationRequiredMixin, TemplateView):
self.request.user.send_security_notice([
_('Two-factor authentication has been enabled.')
])
self.request.user.update_session_token()
update_session_auth_hash(self.request, self.request.user)
return redirect(reverse('control:user.settings.2fa'))
@@ -540,6 +548,8 @@ class User2FADisableView(RecentAuthenticationRequiredMixin, TemplateView):
self.request.user.send_security_notice([
_('Two-factor authentication has been disabled.')
])
self.request.user.update_session_token()
update_session_auth_hash(self.request, self.request.user)
return redirect(reverse('control:user.settings.2fa'))
@@ -555,6 +565,8 @@ class User2FARegenerateEmergencyView(RecentAuthenticationRequiredMixin, Template
self.request.user.send_security_notice([
_('Your two-factor emergency codes have been regenerated.')
])
self.request.user.update_session_token()
update_session_auth_hash(self.request, self.request.user)
messages.success(request, _('Your emergency codes have been newly generated. Remember to store them in a safe '
'place in case you lose access to your devices.'))
return redirect(reverse('control:user.settings.2fa'))