core: properly handle invites; audit: log invite creation and usage

This commit is contained in:
Jens Langhammer 2018-12-10 14:05:27 +01:00
parent 274c9daded
commit 64c8458c90
4 changed files with 50 additions and 3 deletions

View File

@ -24,6 +24,7 @@ class AuditEntry(UUIDModel):
ACTION_SUSPICIOUS_REQUEST = 'suspicious_request' ACTION_SUSPICIOUS_REQUEST = 'suspicious_request'
ACTION_SIGN_UP = 'sign_up' ACTION_SIGN_UP = 'sign_up'
ACTION_PASSWORD_RESET = 'password_reset' ACTION_PASSWORD_RESET = 'password_reset'
ACTION_INVITE_CREATED = 'invite_created'
ACTION_INVITE_USED = 'invite_used' ACTION_INVITE_USED = 'invite_used'
ACTIONS = ( ACTIONS = (
(ACTION_LOGIN, ACTION_LOGIN), (ACTION_LOGIN, ACTION_LOGIN),
@ -33,6 +34,7 @@ class AuditEntry(UUIDModel):
(ACTION_SUSPICIOUS_REQUEST, ACTION_SUSPICIOUS_REQUEST), (ACTION_SUSPICIOUS_REQUEST, ACTION_SUSPICIOUS_REQUEST),
(ACTION_SIGN_UP, ACTION_SIGN_UP), (ACTION_SIGN_UP, ACTION_SIGN_UP),
(ACTION_PASSWORD_RESET, ACTION_PASSWORD_RESET), (ACTION_PASSWORD_RESET, ACTION_PASSWORD_RESET),
(ACTION_INVITE_CREATED, ACTION_INVITE_CREATED),
(ACTION_INVITE_USED, ACTION_INVITE_USED), (ACTION_INVITE_USED, ACTION_INVITE_USED),
) )

View File

@ -4,6 +4,7 @@ from django.contrib.auth.signals import (user_logged_in, user_logged_out,
from django.dispatch import receiver from django.dispatch import receiver
from passbook.audit.models import AuditEntry from passbook.audit.models import AuditEntry
from passbook.core.signals import invite_created, invite_used, user_signed_up
@receiver(user_logged_in) @receiver(user_logged_in)
@ -16,6 +17,21 @@ def on_user_logged_out(sender, request, user, **kwargs):
"""Log successfully logout""" """Log successfully logout"""
AuditEntry.create(AuditEntry.ACTION_LOGOUT, request) AuditEntry.create(AuditEntry.ACTION_LOGOUT, request)
@receiver(user_signed_up)
def on_user_signed_up(sender, request, user, **kwargs):
"""Log successfully signed up"""
AuditEntry.create(AuditEntry.ACTION_SIGN_UP, request)
@receiver(invite_created)
def on_invite_created(sender, request, invite, **kwargs):
"""Log Invite creation"""
AuditEntry.create(AuditEntry.ACTION_INVITE_CREATED, request, invite_uuid=invite.uuid)
@receiver(invite_used)
def on_invite_used(sender, request, invite, **kwargs):
"""Log Invite usage"""
AuditEntry.create(AuditEntry.ACTION_INVITE_USED, request, invite_uuid=invite.uuid)
@receiver(user_login_failed) @receiver(user_login_failed)
def on_user_login_failed(sender, request, user, **kwargs): def on_user_login_failed(sender, request, user, **kwargs):
"""Log failed login attempt""" """Log failed login attempt"""

12
passbook/core/signals.py Normal file
View File

@ -0,0 +1,12 @@
"""passbook core signals"""
from django.core.signals import Signal
# from django.db.models.signals import post_save, pre_delete
# from django.dispatch import receiver
# from passbook.core.models import Invite, User
user_signed_up = Signal(providing_args=['request', 'user'])
# TODO: Send this signal in admin interface
invite_created = Signal(providing_args=['request', 'invite'])
invite_used = Signal(providing_args=['request', 'invite', 'user'])

View File

@ -13,6 +13,7 @@ from django.views.generic import FormView
from passbook.core.forms.authentication import LoginForm, SignUpForm from passbook.core.forms.authentication import LoginForm, SignUpForm
from passbook.core.models import Invite, User from passbook.core.models import Invite, User
from passbook.core.signals import invite_used, user_signed_up
from passbook.lib.config import CONFIG from passbook.lib.config import CONFIG
LOGGER = getLogger(__name__) LOGGER = getLogger(__name__)
@ -117,7 +118,10 @@ class SignUpView(UserPassesTestMixin, FormView):
template_name = 'login/form.html' template_name = 'login/form.html'
form_class = SignUpForm form_class = SignUpForm
success_url = '.' success_url = '.'
# Invite insatnce, if invite link was used
_invite = None _invite = None
# Instance of newly created user
_user = None
# Allow only not authenticated users to login # Allow only not authenticated users to login
def test_func(self): def test_func(self):
@ -150,14 +154,23 @@ class SignUpView(UserPassesTestMixin, FormView):
def form_valid(self, form: SignUpForm) -> HttpResponse: def form_valid(self, form: SignUpForm) -> HttpResponse:
"""Create user""" """Create user"""
SignUpView.create_user(form.cleaned_data, self.request) self._user = SignUpView.create_user(form.cleaned_data, self.request)
if self._invite: self.consume_invite()
self._invite.delete()
messages.success(self.request, _("Successfully signed up!")) messages.success(self.request, _("Successfully signed up!"))
LOGGER.debug("Successfully signed up %s", LOGGER.debug("Successfully signed up %s",
form.cleaned_data.get('email')) form.cleaned_data.get('email'))
return redirect(reverse('passbook_core:auth-login')) return redirect(reverse('passbook_core:auth-login'))
def consume_invite(self):
"""Consume invite if an invite was used"""
if self._invite:
invite_used.send(
sender=self,
request=self.request,
invite=self._invite,
user=self._user)
self._invite.delete()
@staticmethod @staticmethod
def create_user(data: Dict, request: HttpRequest = None) -> User: def create_user(data: Dict, request: HttpRequest = None) -> User:
"""Create user from data """Create user from data
@ -183,6 +196,10 @@ class SignUpView(UserPassesTestMixin, FormView):
new_user.set_password(data.get('password')) new_user.set_password(data.get('password'))
new_user.save() new_user.save()
# Send signal for other auth sources # Send signal for other auth sources
user_signed_up.send(
sender=SignUpView,
user=new_user,
request=request)
# try: # try:
# TODO: Create signal for signup # TODO: Create signal for signup
# on_user_sign_up.send( # on_user_sign_up.send(