diff --git a/src/pretix/api/serializers/organizer.py b/src/pretix/api/serializers/organizer.py index 754dc2d657..6389298df7 100644 --- a/src/pretix/api/serializers/organizer.py +++ b/src/pretix/api/serializers/organizer.py @@ -570,6 +570,7 @@ class OrganizerSettingsSerializer(SettingsSerializer): # should not be included! 'customer_accounts', 'customer_accounts_native', + 'customer_accounts_to_oidc', 'customer_accounts_link_by_email', 'customer_accounts_require_login_for_order_access', 'invoice_regenerate_allowed', diff --git a/src/pretix/base/settings.py b/src/pretix/base/settings.py index ec6224e768..7195465216 100644 --- a/src/pretix/base/settings.py +++ b/src/pretix/base/settings.py @@ -181,6 +181,19 @@ DEFAULTS = { widget=forms.CheckboxInput(attrs={'data-display-dependency': '#id_settings-customer_accounts'}), ) }, + 'customer_accounts_to_oidc': { + 'default': 'False', + 'type': bool, + 'form_class': forms.BooleanField, + 'serializer_class': serializers.BooleanField, + 'form_kwargs': dict( + label=_("Convert existing customers to single-sign-on accounts when logging in through single-sign-on provider"), + help_text=_( + "If disabled, pretix does not allow to log in through a single-sign-on provider if the customer is registered with email and password." + ), + widget=forms.CheckboxInput(attrs={'data-display-dependency': '#id_settings-customer_accounts'}), + ) + }, 'customer_accounts_require_login_for_order_access': { 'default': 'False', 'type': bool, diff --git a/src/pretix/control/forms/organizer.py b/src/pretix/control/forms/organizer.py index 0078562506..d91b3e685d 100644 --- a/src/pretix/control/forms/organizer.py +++ b/src/pretix/control/forms/organizer.py @@ -600,6 +600,7 @@ class OrganizerSettingsForm(SettingsForm): 'allowed_restricted_plugins', 'customer_accounts', 'customer_accounts_native', + 'customer_accounts_to_oidc', 'customer_accounts_link_by_email', 'customer_accounts_require_login_for_order_access', 'invoice_regenerate_allowed', diff --git a/src/pretix/control/templates/pretixcontrol/organizers/edit.html b/src/pretix/control/templates/pretixcontrol/organizers/edit.html index 960c6fb4f5..010c1901b5 100644 --- a/src/pretix/control/templates/pretixcontrol/organizers/edit.html +++ b/src/pretix/control/templates/pretixcontrol/organizers/edit.html @@ -132,6 +132,7 @@ {% trans "Customer accounts" %} {% bootstrap_field sform.customer_accounts layout="control" %} {% bootstrap_field sform.customer_accounts_native layout="control" %} + {% bootstrap_field sform.customer_accounts_to_oidc layout="control" %} {% bootstrap_field sform.customer_accounts_require_login_for_order_access layout="control" %} {% bootstrap_field sform.customer_accounts_link_by_email layout="control" %} {% bootstrap_field sform.name_scheme layout="control" %} diff --git a/src/pretix/presale/views/customer.py b/src/pretix/presale/views/customer.py index 5e15cfe442..b002711a6f 100644 --- a/src/pretix/presale/views/customer.py +++ b/src/pretix/presale/views/customer.py @@ -864,11 +864,36 @@ class SSOLoginReturnView(RedirectBackMixin, View): identifier=identifier, ) except Customer.DoesNotExist: - return self._fail( - _('We were unable to use your login since the email address {email} is already used for a ' - 'different account in this system.').format(email=profile['email']), - popup_origin, - ) + # no race-condition, try to convert to oidc? + if self.request.organizer.settings.customer_accounts_to_oidc: + try: + customer = self.request.organizer.customers.get( + email=profile['email'], + ) + update_fields = { + 'provider': self.provider.pk, + 'external_identifier': str(profile['uid']), + 'identifier': identifier, + 'is_active': True, + 'is_verified': True, + } + if name_parts: + update_fields['name_parts'] = name_parts + if profile.get('phone'): + update_fields['phone'] = profile.get('phone') + customer.update(**update_fields) + except Customer.DoesNotExist: + # should actually never happen + return self._fail( + _('We were unable to use your login since either the email address is unknown in this system.'), + popup_origin, + ) + else: + return self._fail( + _('We were unable to use your login since the email address {email} is already used for a ' + 'different account in this system.').format(email=profile['email']), + popup_origin, + ) else: if customer.is_active and customer.email != profile['email']: customer.email = profile['email']