Compare commits

...

4 Commits

Author SHA1 Message Date
Richard Schreiber 9a233a499e fix flake8 2026-06-23 15:05:31 +02:00
Richard Schreiber 89d32a9bcf add tests 2026-06-23 15:02:06 +02:00
Richard Schreiber df2348a74a set password unusable 2026-06-23 15:02:02 +02:00
Richard Schreiber 8138d2156a Allow to convert customers to OIDC on login (Z#23237685) 2026-06-23 14:33:53 +02:00
6 changed files with 62 additions and 5 deletions
+1
View File
@@ -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',
+13
View File
@@ -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,
+1
View File
@@ -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',
@@ -132,6 +132,7 @@
<legend>{% trans "Customer accounts" %}</legend>
{% 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" %}
+29 -5
View File
@@ -864,11 +864,35 @@ 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'],
)
customer.set_unusable_password()
customer.provider = self.provider
customer.external_identifier = str(profile['uid'])
customer.identifier = identifier
customer.is_active = True
customer.is_verified = True
if name_parts:
customer.name_parts = name_parts
if profile.get('phone'):
customer.phone = profile.get('phone')
customer.save()
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']
+17
View File
@@ -438,6 +438,23 @@ def test_org_sso_login_new_customer_email_conflict(env, client, provider):
_sso_login(client, provider, 'new@example.net', expect_fail=True)
@pytest.mark.django_db(transaction=True)
def test_org_sso_convert_customer_on_login(env, client, provider):
organizer = env[0]
organizer.settings.customer_accounts_to_oidc = True
with scopes_disabled():
customer = organizer.customers.create(email='new@example.net', is_verified=True, is_active=False)
customer.set_password('foo')
customer.save()
_sso_login(client, provider, 'new@example.net')
customer.refresh_from_db()
assert customer.provider
assert customer.identifier
assert not customer.has_usable_password()
@pytest.mark.django_db
@pytest.mark.parametrize("url", [
"account/change",