def post(self, request, *args, **kwargs): r = request.POST.get("webauthn", "") valid = False if 'webauthn_challenge' in self.request.session and r.startswith('{'): challenge = self.request.session['webauthn_challenge'] resp = json.loads(r) try: devices = [ WebAuthnDevice.objects.get(user=self.request.user, credential_id=resp.get("id")) ] except WebAuthnDevice.DoesNotExist: devices = U2FDevice.objects.filter(user=self.request.user) for d in devices: try: wu = d.webauthnuser if isinstance(d, U2FDevice): # RP_ID needs to be appId for U2F devices, but we can't # set it that way in U2FDevice.webauthnuser, since that # breaks the frontend part. wu.rp_id = settings.SITE_URL webauthn_assertion_response = webauthn.WebAuthnAssertionResponse( wu, resp, challenge, settings.SITE_URL, uv_required=False # User Verification ) sign_count = webauthn_assertion_response.verify() except Exception: logger.exception('U2F login failed') else: if isinstance(d, WebAuthnDevice): d.sign_count = sign_count d.save() valid = True break valid = valid or self.form.is_valid() if valid: t = int(time.time()) request.session['pretix_auth_login_time'] = t request.session['pretix_auth_last_used'] = t next_url = get_auth_backends()[ request.user.auth_backend].get_next_url(request) if next_url and url_has_allowed_host_and_scheme( next_url, allowed_hosts=None): return redirect(next_url) return redirect(reverse('control:index')) else: messages.error( request, _('The password you entered was invalid, please try again.')) return self.get(request, *args, **kwargs)
def register(request): """ Render and process a basic registration form. """ if not settings.PRETIX_REGISTRATION or 'native' not in get_auth_backends(): raise PermissionDenied('Registration is disabled') ctx = {} if request.user.is_authenticated: return redirect(request.GET.get("next", 'control:index')) if request.method == 'POST': form = RegistrationForm(data=request.POST) if form.is_valid(): user = User.objects.create_user( form.cleaned_data['email'], form.cleaned_data['password'], locale=request.LANGUAGE_CODE, timezone=request.timezone if hasattr(request, 'timezone') else settings.TIME_ZONE) user = authenticate(request=request, email=user.email, password=form.cleaned_data['password']) user.log_action('pretix.control.auth.user.created', user=user) auth_login(request, user) request.session['pretix_auth_login_time'] = int(time.time()) request.session['pretix_auth_long_session'] = ( settings.PRETIX_LONG_SESSIONS and form.cleaned_data.get('keep_logged_in', False)) return redirect('control:index') else: form = RegistrationForm() ctx['form'] = form return render(request, 'pretixcontrol/auth/register.html', ctx)
def process_login(request, user, keep_logged_in): """ This method allows you to return a response to a successful log-in. This will set all session values correctly and redirect to either the URL specified in the ``next`` parameter, or the 2FA login screen, or the dashboard. :return: This method returns a ``HttpResponse``. """ request.session[ 'pretix_auth_long_session'] = settings.PRETIX_LONG_SESSIONS and keep_logged_in next_url = get_auth_backends()[user.auth_backend].get_next_url(request) if user.require_2fa: request.session['pretix_auth_2fa_user'] = user.pk request.session['pretix_auth_2fa_time'] = str(int(time.time())) twofa_url = reverse('control:auth.login.2fa') if next_url and url_has_allowed_host_and_scheme(next_url, allowed_hosts=None): twofa_url += '?next=' + quote(next_url) return redirect(twofa_url) else: auth_login(request, user) request.session['pretix_auth_login_time'] = int(time.time()) if next_url and url_has_allowed_host_and_scheme(next_url, allowed_hosts=None): return redirect(next_url) return redirect(reverse('control:index'))
def get_context_data(self, **kwargs): ctx = super().get_context_data(**kwargs) ctx['teams'] = self.object.teams.select_related('organizer') b = get_auth_backends() ctx['backend'] = (b[self.object.auth_backend].verbose_name if self.object.auth_backend in b else self.object.auth_backend) return ctx
def form(self): return ReauthForm( user=self.request.user, backend=get_auth_backends()[self.request.user.auth_backend], request=self.request, data=self.request.POST if self.request.method == "POST" else None, initial={ 'email': self.request.user.email, })
def get(self, request, *args, **kwargs): u = get_auth_backends()[ request.user.auth_backend].request_authenticate(request) if u and u == request.user: if "next" in request.GET and is_safe_url(request.GET.get("next"), allowed_hosts=None): return redirect(request.GET.get("next")) return redirect(reverse('control:index')) return super().get(request, *args, **kwargs)
def get(self, request, *args, **kwargs): backend = get_auth_backends()[request.user.auth_backend] u = backend.request_authenticate(request) if u and u == request.user: next_url = backend.get_next_url(request) if next_url and url_has_allowed_host_and_scheme( next_url, allowed_hosts=None): return redirect(next_url) return redirect(reverse('control:index')) return super().get(request, *args, **kwargs)
def get(self, request, *args, **kwargs): backend = get_auth_backends()[request.user.auth_backend] u = backend.request_authenticate(request) if u and u == request.user: next_url = backend.get_next_url(request) t = int(time.time()) request.session['pretix_auth_login_time'] = t request.session['pretix_auth_last_used'] = t if next_url and url_has_allowed_host_and_scheme(next_url, allowed_hosts=None): return redirect(next_url) return redirect(reverse('control:index')) return super().get(request, *args, **kwargs)
def login(request): """ Render and process a most basic login form. Takes an URL as GET parameter "next" for redirection after successful login """ ctx = {} backenddict = get_auth_backends() backends = sorted(backenddict.values(), key=lambda b: (b.identifier != "native", b.verbose_name)) for b in backends: u = b.request_authenticate(request) if u and u.auth_backend == b.identifier: return process_login(request, u, False) b.url = b.authentication_url(request) backend = backenddict.get(request.GET.get('backend', 'native'), backends[0]) if not backend.visible: backend = [b for b in backends if b.visible][0] if request.user.is_authenticated: next_url = backend.get_next_url(request) or 'control:index' if next_url and url_has_allowed_host_and_scheme(next_url, allowed_hosts=None): return redirect(next_url) return redirect(reverse('control:index')) if request.method == 'POST': form = LoginForm(backend=backend, data=request.POST, request=request) if form.is_valid( ) and form.user_cache and form.user_cache.auth_backend == backend.identifier: return process_login( request, form.user_cache, form.cleaned_data.get('keep_logged_in', False)) else: form = LoginForm(backend=backend, request=request) ctx['form'] = form ctx['can_register'] = settings.PRETIX_REGISTRATION ctx['can_reset'] = settings.PRETIX_PASSWORD_RESET ctx['backends'] = backends ctx['backend'] = backend return render(request, 'pretixcontrol/auth/login.html', ctx)
def create(self, validated_data): if 'email' in validated_data: try: user = User.objects.get(email__iexact=validated_data['email']) except User.DoesNotExist: if self.context['team'].invites.filter( email__iexact=validated_data['email']).exists(): raise ValidationError( _('This user already has been invited for this team.')) if 'native' not in get_auth_backends(): raise ValidationError( 'Users need to have a pretix account before they can be invited.' ) invite = self.context['team'].invites.create( email=validated_data['email']) self._send_invite(invite) invite.team.log_action('pretix.team.invite.created', data={'email': validated_data['email']}, **self.context['log_kwargs']) return invite else: if self.context['team'].members.filter(pk=user.pk).exists(): raise ValidationError( _('This user already has permissions for this team.')) self.context['team'].members.add(user) self.context['team'].log_action('pretix.team.member.added', data={ 'email': user.email, 'user': user.pk, }, **self.context['log_kwargs']) return TeamInvite(email=user.email) else: raise ValidationError('No email address given.')
def dispatch(self, request, *args, **kwargs): if not settings.PRETIX_PASSWORD_RESET or 'native' not in get_auth_backends( ): raise PermissionDenied('Registration is disabled') return super().dispatch(request, *args, **kwargs)
def invite(request, token): """ Registration form in case of an invite """ ctx = {} if 'native' not in get_auth_backends(): raise PermissionDenied('Invites are disabled') try: inv = TeamInvite.objects.get(token=token) except TeamInvite.DoesNotExist: messages.error( request, _('You used an invalid link. Please copy the link from your email to the address bar ' 'and make sure it is correct and that the link has not been used before.' )) return redirect('control:auth.login') if request.user.is_authenticated: if inv.team.members.filter(pk=request.user.pk).exists(): messages.error( request, _('You cannot accept the invitation for "{}" as you already are part of ' 'this team.').format(inv.team.name)) return redirect('control:index') else: with transaction.atomic(): inv.team.members.add(request.user) inv.team.log_action('pretix.team.member.joined', data={ 'email': request.user.email, 'invite_email': inv.email, 'user': request.user.pk }) inv.delete() messages.success( request, _('You are now part of the team "{}".').format(inv.team.name)) return redirect('control:index') if request.method == 'POST': form = RegistrationForm(data=request.POST) with transaction.atomic(): valid = form.is_valid() if valid: user = User.objects.create_user( form.cleaned_data['email'], form.cleaned_data['password'], locale=request.LANGUAGE_CODE, timezone=request.timezone if hasattr(request, 'timezone') else settings.TIME_ZONE) user = authenticate(request=request, email=user.email, password=form.cleaned_data['password']) user.log_action('pretix.control.auth.user.created', user=user) auth_login(request, user) request.session['pretix_auth_login_time'] = int(time.time()) request.session['pretix_auth_long_session'] = ( settings.PRETIX_LONG_SESSIONS and form.cleaned_data.get('keep_logged_in', False)) inv.team.members.add(request.user) inv.team.log_action('pretix.team.member.joined', data={ 'email': user.email, 'invite_email': inv.email, 'user': user.pk }) inv.delete() messages.success( request, _('Welcome to pretix! You are now part of the team "{}".'). format(inv.team.name)) return redirect('control:index') else: form = RegistrationForm(initial={'email': inv.email}) ctx['form'] = form return render(request, 'pretixcontrol/auth/invite.html', ctx)
def post(self, request, *args, **kwargs): self.object = self.get_object() if 'remove-member' in request.POST: try: user = User.objects.get(pk=request.POST.get('remove-member')) except (User.DoesNotExist, ValueError): pass else: other_admin_teams = self.request.organizer.teams.exclude( pk=self.object.pk).filter(can_change_teams=True, members__isnull=False).exists() if not other_admin_teams and self.object.can_change_teams and self.object.members.count( ) == 1: messages.error( self.request, _('You cannot remove the last member from this team as no one would ' 'be left with the permission to change teams.')) return redirect(self.get_success_url()) else: self.object.members.remove(user) self.object.log_action('pretix.team.member.removed', user=self.request.user, data={ 'email': user.email, 'user': user.pk }) messages.success( self.request, _('The member has been removed from the team.')) return redirect(self.get_success_url()) elif 'remove-invite' in request.POST: try: invite = self.object.invites.get( pk=request.POST.get('remove-invite')) except (TeamInvite.DoesNotExist, ValueError): messages.error(self.request, _('Invalid invite selected.')) return redirect(self.get_success_url()) else: invite.delete() self.object.log_action('pretix.team.invite.deleted', user=self.request.user, data={'email': invite.email}) messages.success(self.request, _('The invite has been revoked.')) return redirect(self.get_success_url()) elif 'resend-invite' in request.POST: try: invite = self.object.invites.get( pk=request.POST.get('resend-invite')) except (TeamInvite.DoesNotExist, ValueError): messages.error(self.request, _('Invalid invite selected.')) return redirect(self.get_success_url()) else: self._send_invite(invite) self.object.log_action('pretix.team.invite.resent', user=self.request.user, data={'email': invite.email}) messages.success(self.request, _('The invite has been resent.')) return redirect(self.get_success_url()) elif 'remove-token' in request.POST: try: token = self.object.tokens.get( pk=request.POST.get('remove-token')) except (TeamAPIToken.DoesNotExist, ValueError): messages.error(self.request, _('Invalid token selected.')) return redirect(self.get_success_url()) else: token.active = False token.save() self.object.log_action('pretix.team.token.deleted', user=self.request.user, data={'name': token.name}) messages.success(self.request, _('The token has been revoked.')) return redirect(self.get_success_url()) elif "user" in self.request.POST and self.add_form.is_valid( ) and self.add_form.has_changed(): try: user = User.objects.get( email__iexact=self.add_form.cleaned_data['user']) except User.DoesNotExist: if self.object.invites.filter(email__iexact=self.add_form. cleaned_data['user']).exists(): messages.error( self.request, _('This user already has been invited for this team.')) return self.get(request, *args, **kwargs) if 'native' not in get_auth_backends(): messages.error( self.request, _('Users need to have a pretix account before they can be invited.' )) return self.get(request, *args, **kwargs) invite = self.object.invites.create( email=self.add_form.cleaned_data['user']) self._send_invite(invite) self.object.log_action( 'pretix.team.invite.created', user=self.request.user, data={'email': self.add_form.cleaned_data['user']}) messages.success( self.request, _('The new member has been invited to the team.')) return redirect(self.get_success_url()) else: if self.object.members.filter(pk=user.pk).exists(): messages.error( self.request, _('This user already has permissions for this team.')) return self.get(request, *args, **kwargs) self.object.members.add(user) self.object.log_action('pretix.team.member.added', user=self.request.user, data={ 'email': user.email, 'user': user.pk, }) messages.success( self.request, _('The new member has been added to the team.')) return redirect(self.get_success_url()) elif "name" in self.request.POST and self.add_token_form.is_valid( ) and self.add_token_form.has_changed(): token = self.object.tokens.create( name=self.add_token_form.cleaned_data['name']) self.object.log_action( 'pretix.team.token.created', user=self.request.user, data={ 'name': self.add_token_form.cleaned_data['name'], 'id': token.pk }) messages.success( self.request, _('A new API token has been created with the following secret: {}\n' 'Please copy this secret to a safe place. You will not be able to ' 'view it again here.').format(token.token)) return redirect(self.get_success_url()) else: messages.error(self.request, _('Your changes could not be saved.')) return self.get(request, *args, **kwargs)