Reduce confusion about customer login with event level domains (#2380)

This commit is contained in:
Raphael Michel
2021-12-15 16:47:08 +01:00
committed by GitHub
parent 0e9600a7bf
commit 5210ac3a78
7 changed files with 337 additions and 50 deletions

View File

@@ -19,8 +19,12 @@
# You should have received a copy of the GNU Affero General Public License along with this program. If not, see
# <https://www.gnu.org/licenses/>.
#
from urllib.parse import quote
from importlib import import_module
from urllib.parse import (
parse_qs, quote, urlencode, urljoin, urlparse, urlsplit, urlunparse,
)
from django.conf import settings
from django.contrib import messages
from django.core.signing import BadSignature, dumps, loads
from django.db import transaction
@@ -38,6 +42,7 @@ from django.views.generic import DeleteView, FormView, ListView, View
from pretix.base.models import Customer, InvoiceAddress, Order, OrderPosition
from pretix.base.services.mail import mail
from pretix.multidomain.models import KnownDomain
from pretix.multidomain.urlreverse import build_absolute_uri, eventreverse
from pretix.presale.forms.customer import (
AuthenticationForm, ChangeInfoForm, ChangePasswordForm, RegistrationForm,
@@ -47,6 +52,8 @@ from pretix.presale.utils import (
customer_login, customer_logout, update_customer_session_auth_hash,
)
SessionStore = import_module(settings.SESSION_ENGINE).SessionStore
class RedirectBackMixin:
redirect_field_name = 'next'
@@ -57,9 +64,14 @@ class RedirectBackMixin:
self.redirect_field_name,
self.request.GET.get(self.redirect_field_name, '')
)
hosts = list(KnownDomain.objects.filter(event__organizer=self.request.organizer).values_list('domainname', flat=True))
siteurlsplit = urlsplit(settings.SITE_URL)
if siteurlsplit.port and siteurlsplit.port not in (80, 443):
hosts = ['%s:%d' % (h, siteurlsplit.port) for h in hosts]
url_is_safe = url_has_allowed_host_and_scheme(
url=redirect_to,
allowed_hosts=None,
allowed_hosts=hosts,
require_https=self.request.is_secure(),
)
return redirect_to if url_is_safe else ''
@@ -96,11 +108,23 @@ class LoginView(RedirectBackMixin, FormView):
def get_success_url(self):
url = self.get_redirect_url()
if getattr(self.request, 'event_domain', False):
default_url = '/'
else:
default_url = eventreverse(self.request.organizer, 'presale:organizer.customer.profile', kwargs={})
return url or default_url
if not url:
return eventreverse(self.request.organizer, 'presale:organizer.customer.profile', kwargs={})
if self.request.GET.get("request_cross_domain_customer_auth") == "true":
otpstore = SessionStore()
otpstore[f'customer_cross_domain_auth_{self.request.organizer.pk}'] = self.request.session.session_key
otpstore.set_expiry(60)
otpstore.save(must_create=True)
otp = otpstore.session_key
u = urlparse(url)
qsl = parse_qs(u.query)
qsl['cross_domain_customer_auth'] = otp
url = urlunparse((u.scheme, u.netloc, u.path, u.params, urlencode(qsl, doseq=True), u.fragment))
return url
def form_valid(self, form):
"""Security check complete. Log the user in."""
@@ -119,25 +143,39 @@ class LogoutView(View):
def get_next_page(self):
if getattr(self.request, 'event_domain', False):
next_page = '/'
# After we cleared the cookies on this domain, redirect to the parent domain to clear cookies as well
next_page = eventreverse(self.request.organizer, 'presale:organizer.customer.logout', kwargs={})
if self.redirect_field_name in self.request.POST or self.redirect_field_name in self.request.GET:
after_next_page = self.request.POST.get(
self.redirect_field_name,
self.request.GET.get(self.redirect_field_name)
)
next_page += '?' + urlencode({
'next': urljoin(f'{self.request.scheme}://{self.request.get_host()}', after_next_page)
})
else:
next_page = eventreverse(self.request.organizer, 'presale:organizer.index', kwargs={})
if (self.redirect_field_name in self.request.POST or
self.redirect_field_name in self.request.GET):
next_page = self.request.POST.get(
self.redirect_field_name,
self.request.GET.get(self.redirect_field_name)
)
url_is_safe = url_has_allowed_host_and_scheme(
url=next_page,
allowed_hosts=None,
require_https=self.request.is_secure(),
)
# Security check -- Ensure the user-originating redirection URL is
# safe.
if not url_is_safe:
next_page = self.request.path
if (self.redirect_field_name in self.request.POST or
self.redirect_field_name in self.request.GET):
next_page = self.request.POST.get(
self.redirect_field_name,
self.request.GET.get(self.redirect_field_name)
)
hosts = list(KnownDomain.objects.filter(event__organizer=self.request.organizer).values_list('domainname', flat=True))
siteurlsplit = urlsplit(settings.SITE_URL)
if siteurlsplit.port and siteurlsplit.port not in (80, 443):
hosts = ['%s:%d' % (h, siteurlsplit.port) for h in hosts]
url_is_safe = url_has_allowed_host_and_scheme(
url=next_page,
allowed_hosts=hosts,
require_https=self.request.is_secure(),
)
# Security check -- Ensure the user-originating redirection URL is
# safe.
if not url_is_safe:
next_page = self.request.path
return next_page