mirror of
https://github.com/pretix/pretix.git
synced 2026-05-05 15:14:04 +00:00
Log out other sessions after email or 2FA changes
This commit is contained in:
20
src/pretix/base/migrations/0147_user_session_token.py
Normal file
20
src/pretix/base/migrations/0147_user_session_token.py
Normal 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),
|
||||
),
|
||||
]
|
||||
@@ -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)
|
||||
|
||||
@@ -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'))
|
||||
|
||||
Reference in New Issue
Block a user