Skip to content

Commit 599fb53

Browse files
fix: removal of temporary saml toggle
1 parent 9110ae0 commit 599fb53

File tree

4 files changed

+67
-118
lines changed

4 files changed

+67
-118
lines changed

common/djangoapps/third_party_auth/management/commands/tests/test_saml.py

Lines changed: 15 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -69,16 +69,16 @@ def setUp(self):
6969
# not processed.
7070
self.saml_config = SAMLConfigurationFactory.create(
7171
enabled=False,
72-
site__domain='testserver.fake',
73-
site__name='testserver.fake'
72+
site__domain='setup.testserver.fake',
73+
site__name='setup.testserver.fake'
7474
)
7575
self.provider_config = SAMLProviderConfigFactory.create(
76-
site__domain='testserver.fake',
77-
site__name='testserver.fake',
78-
slug='test-shib',
79-
name='TestShib College',
80-
entity_id='https://idp.testshib.org/idp/shibboleth',
81-
metadata_source='https://www.testshib.org/metadata/testshib-providers.xml',
76+
site__domain='setup.testserver.fake',
77+
site__name='setup.testserver.fake',
78+
slug='setup-test-shib',
79+
name='Setup TestShib College',
80+
entity_id='https://idp.testshib.org/idp/setup-shibboleth',
81+
metadata_source='https://www.testshib.org/metadata/setup-testshib-providers.xml',
8282
)
8383

8484
def _setup_test_configs_for_run_checks(self):
@@ -169,7 +169,7 @@ def test_fetch_saml_metadata(self):
169169
# Create enabled configurations
170170
self.__create_saml_configurations__()
171171

172-
expected = "\nDone.\n1 provider(s) found in database.\n0 skipped and 1 attempted.\n1 updated and 0 failed.\n"
172+
expected = "\nDone.\n2 provider(s) found in database.\n1 skipped and 1 attempted.\n1 updated and 0 failed.\n"
173173
call_command("saml", pull=True, stdout=self.stdout)
174174
assert expected in self.stdout.getvalue()
175175

@@ -182,7 +182,7 @@ def test_fetch_saml_metadata_failure(self):
182182
# Create enabled configurations
183183
self.__create_saml_configurations__()
184184

185-
expected = "\nDone.\n1 provider(s) found in database.\n0 skipped and 1 attempted.\n0 updated and 1 failed.\n"
185+
expected = "\nDone.\n2 provider(s) found in database.\n1 skipped and 1 attempted.\n0 updated and 1 failed.\n"
186186

187187
with self.assertRaisesRegex(CommandError, r"HTTPError: 404 Client Error"):
188188
call_command("saml", pull=True, stdout=self.stdout)
@@ -228,7 +228,7 @@ def test_fetch_multiple_providers_data(self):
228228
}
229229
)
230230

231-
expected = '\n3 provider(s) found in database.\n0 skipped and 3 attempted.\n2 updated and 1 failed.\n'
231+
expected = '\n4 provider(s) found in database.\n1 skipped and 3 attempted.\n2 updated and 1 failed.\n'
232232
with self.assertRaisesRegex(CommandError, r"MetadataParseError: Can't find EntityDescriptor for entityID"):
233233
call_command("saml", pull=True, stdout=self.stdout)
234234
assert expected in self.stdout.getvalue()
@@ -250,8 +250,8 @@ def test_fetch_multiple_providers_data(self):
250250
}
251251
)
252252

253-
# Four configurations -- one will be skipped and three attempted, with similar results.
254-
expected = '\nDone.\n4 provider(s) found in database.\n1 skipped and 3 attempted.\n0 updated and 1 failed.\n'
253+
# Five configurations -- two will be skipped and three attempted, with similar results.
254+
expected = '\nDone.\n5 provider(s) found in database.\n2 skipped and 3 attempted.\n0 updated and 1 failed.\n'
255255
with self.assertRaisesRegex(CommandError, r"MetadataParseError: Can't find EntityDescriptor for entityID"):
256256
call_command("saml", pull=True, stdout=self.stdout)
257257
assert expected in self.stdout.getvalue()
@@ -266,7 +266,7 @@ def test_saml_request_exceptions(self, mocked_get):
266266

267267
mocked_get.side_effect = exceptions.SSLError
268268

269-
expected = "\nDone.\n1 provider(s) found in database.\n0 skipped and 1 attempted.\n0 updated and 1 failed.\n"
269+
expected = "\nDone.\n2 provider(s) found in database.\n1 skipped and 1 attempted.\n0 updated and 1 failed.\n"
270270

271271
with self.assertRaisesRegex(CommandError, "SSLError:"):
272272
call_command("saml", pull=True, stdout=self.stdout)
@@ -323,7 +323,7 @@ def test_xml_parse_exceptions(self, mocked_get):
323323
# create enabled configuration
324324
self.__create_saml_configurations__()
325325

326-
expected = "\nDone.\n1 provider(s) found in database.\n0 skipped and 1 attempted.\n0 updated and 1 failed.\n"
326+
expected = "\nDone.\n2 provider(s) found in database.\n1 skipped and 1 attempted.\n0 updated and 1 failed.\n"
327327

328328
with self.assertRaisesRegex(CommandError, "XMLSyntaxError:"):
329329
call_command("saml", pull=True, stdout=self.stdout)

common/djangoapps/third_party_auth/signals/handlers.py

Lines changed: 22 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,6 @@
77
from edx_django_utils.monitoring import set_custom_attribute
88

99
from common.djangoapps.third_party_auth.models import SAMLConfiguration, SAMLProviderConfig
10-
from common.djangoapps.third_party_auth.toggles import ENABLE_SAML_CONFIG_SIGNAL_HANDLERS
1110

1211

1312
@receiver(post_save, sender=SAMLConfiguration)
@@ -20,10 +19,6 @@ def update_saml_provider_configs_on_configuration_change(sender, instance, creat
2019
configuration version, ensuring all providers remain aligned with the most
2120
current settings.
2221
"""
23-
# .. custom_attribute_name: saml_config_signal.enabled
24-
# .. custom_attribute_description: Tracks whether the SAML config signal handler is enabled.
25-
set_custom_attribute('saml_config_signal.enabled', ENABLE_SAML_CONFIG_SIGNAL_HANDLERS.is_enabled())
26-
2722
# .. custom_attribute_name: saml_config_signal.new_config_id
2823
# .. custom_attribute_description: Records the ID of the new SAML configuration instance.
2924
set_custom_attribute('saml_config_signal.new_config_id', instance.id)
@@ -32,26 +27,25 @@ def update_saml_provider_configs_on_configuration_change(sender, instance, creat
3227
# .. custom_attribute_description: Records the slug of the SAML configuration instance.
3328
set_custom_attribute('saml_config_signal.slug', instance.slug)
3429

35-
if ENABLE_SAML_CONFIG_SIGNAL_HANDLERS.is_enabled():
36-
try:
37-
# Find all existing SAMLProviderConfig instances (current_set) that should be
38-
# pointing to this slug but are pointing to an older version
39-
existing_providers = SAMLProviderConfig.objects.current_set().filter(
40-
saml_configuration__site_id=instance.site_id,
41-
saml_configuration__slug=instance.slug
42-
).exclude(saml_configuration_id=instance.id).exclude(saml_configuration_id__isnull=True)
43-
44-
updated_count = 0
45-
for provider_config in existing_providers:
46-
provider_config.saml_configuration = instance
47-
provider_config.save()
48-
updated_count += 1
49-
50-
# .. custom_attribute_name: saml_config_signal.updated_count
51-
# .. custom_attribute_description: The number of SAMLProviderConfig records updated to point to the new configuration.
52-
set_custom_attribute('saml_config_signal.updated_count', updated_count)
53-
54-
except Exception as e: # pylint: disable=broad-except
55-
# .. custom_attribute_name: saml_config_signal.error_message
56-
# .. custom_attribute_description: Records any error message that occurs during SAML provider config updates.
57-
set_custom_attribute('saml_config_signal.error_message', str(e))
30+
try:
31+
# Find all existing SAMLProviderConfig instances (current_set) that should be
32+
# pointing to this slug but are pointing to an older version
33+
existing_providers = SAMLProviderConfig.objects.current_set().filter(
34+
saml_configuration__site_id=instance.site_id,
35+
saml_configuration__slug=instance.slug
36+
).exclude(saml_configuration_id=instance.id).exclude(saml_configuration_id__isnull=True)
37+
38+
updated_count = 0
39+
for provider_config in existing_providers:
40+
provider_config.saml_configuration = instance
41+
provider_config.save()
42+
updated_count += 1
43+
44+
# .. custom_attribute_name: saml_config_signal.updated_count
45+
# .. custom_attribute_description: The number of SAMLProviderConfig records updated to point to the new configuration.
46+
set_custom_attribute('saml_config_signal.updated_count', updated_count)
47+
48+
except Exception as e: # pylint: disable=broad-except
49+
# .. custom_attribute_name: saml_config_signal.error_message
50+
# .. custom_attribute_description: Records any error message that occurs during SAML provider config updates.
51+
set_custom_attribute('saml_config_signal.error_message', str(e))

common/djangoapps/third_party_auth/signals/tests/test_handlers.py

Lines changed: 29 additions & 54 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@
55
import ddt
66
from unittest import mock
77
from unittest.mock import call
8-
from django.test import TestCase, override_settings
8+
from django.test import TestCase
99
from django.contrib.sites.models import Site
1010
from common.djangoapps.third_party_auth.tests.factories import SAMLConfigurationFactory, SAMLProviderConfigFactory
1111
from common.djangoapps.third_party_auth.models import SAMLProviderConfig
@@ -34,64 +34,42 @@ def setUp(self):
3434
)
3535

3636
@mock.patch('common.djangoapps.third_party_auth.signals.handlers.set_custom_attribute')
37-
def test_saml_config_signal_handlers_disabled(self, mock_set_custom_attribute):
37+
def test_saml_config_signal_handlers_with_error(self, mock_set_custom_attribute):
3838
"""
39-
Test behavior when SAML config signal handlers are disabled.
39+
Test error handling when signal handlers encounter an exception.
4040
41-
Verifies that basic attributes are set but no provider updates are attempted.
41+
Verifies that error information is properly captured when provider updates fail.
4242
"""
43-
with override_settings(ENABLE_SAML_CONFIG_SIGNAL_HANDLERS=False):
43+
error_message = "Test error"
44+
# Simulate an exception in the provider config update logic
45+
with mock.patch(
46+
'common.djangoapps.third_party_auth.models.SAMLProviderConfig.objects.current_set',
47+
side_effect=Exception(error_message)
48+
):
4449
self.saml_config.entity_id = 'https://updated.example.com'
4550
self.saml_config.save()
4651

47-
expected_calls = [
48-
call('saml_config_signal.enabled', False),
49-
call('saml_config_signal.new_config_id', self.saml_config.id),
50-
call('saml_config_signal.slug', 'test-config'),
51-
]
52-
53-
mock_set_custom_attribute.assert_has_calls(expected_calls, any_order=False)
54-
assert mock_set_custom_attribute.call_count == 3
52+
expected_calls = [
53+
call('saml_config_signal.new_config_id', self.saml_config.id),
54+
call('saml_config_signal.slug', 'test-config'),
55+
]
5556

56-
@mock.patch('common.djangoapps.third_party_auth.signals.handlers.set_custom_attribute')
57-
def test_saml_config_signal_handlers_with_error(self, mock_set_custom_attribute):
58-
"""
59-
Test error handling when signal handlers encounter an exception.
57+
mock_set_custom_attribute.assert_has_calls(expected_calls, any_order=False)
58+
assert mock_set_custom_attribute.call_count == 3
6059

61-
Verifies that error information is properly captured when provider updates fail.
62-
"""
63-
error_message = "Test error"
64-
with override_settings(ENABLE_SAML_CONFIG_SIGNAL_HANDLERS=True):
65-
# Simulate an exception in the provider config update logic
66-
with mock.patch(
67-
'common.djangoapps.third_party_auth.models.SAMLProviderConfig.objects.current_set',
68-
side_effect=Exception(error_message)
69-
):
70-
self.saml_config.entity_id = 'https://updated.example.com'
71-
self.saml_config.save()
72-
73-
expected_calls = [
74-
call('saml_config_signal.enabled', True),
75-
call('saml_config_signal.new_config_id', self.saml_config.id),
76-
call('saml_config_signal.slug', 'test-config'),
77-
]
78-
79-
mock_set_custom_attribute.assert_has_calls(expected_calls, any_order=False)
80-
assert mock_set_custom_attribute.call_count == 4
81-
82-
# Verify error message was logged
83-
mock_set_custom_attribute.assert_any_call(
84-
'saml_config_signal.error_message',
85-
mock.ANY
86-
)
87-
error_calls = [
88-
call for call in mock_set_custom_attribute.mock_calls
89-
if call[1][0] == 'saml_config_signal.error_message'
90-
]
91-
assert error_message in error_calls[0][1][1], (
92-
f"Expected '{error_message}' in error message, "
93-
f"got: {error_calls[0][1][1]}"
94-
)
60+
# Verify error message was logged
61+
mock_set_custom_attribute.assert_any_call(
62+
'saml_config_signal.error_message',
63+
mock.ANY
64+
)
65+
error_calls = [
66+
call for call in mock_set_custom_attribute.mock_calls
67+
if call[1][0] == 'saml_config_signal.error_message'
68+
]
69+
assert error_message in error_calls[0][1][1], (
70+
f"Expected '{error_message}' in error message, "
71+
f"got: {error_calls[0][1][1]}"
72+
)
9573

9674
def _get_current_provider(self, slug):
9775
"""
@@ -125,7 +103,6 @@ def _get_site(self, site_id):
125103
)
126104
@ddt.unpack
127105
@mock.patch('common.djangoapps.third_party_auth.signals.handlers.set_custom_attribute')
128-
@override_settings(ENABLE_SAML_CONFIG_SIGNAL_HANDLERS=True)
129106
def test_saml_provider_config_updates(self, provider_site_id, provider_slug,
130107
signal_saml_site_id, signal_saml_slug, is_provider_updated,
131108
mock_set_custom_attribute):
@@ -154,7 +131,6 @@ def test_saml_provider_config_updates(self, provider_site_id, provider_slug,
154131
current_provider = self._get_current_provider(provider_slug)
155132

156133
expected_calls = [
157-
call('saml_config_signal.enabled', True),
158134
call('saml_config_signal.new_config_id', new_saml_config.id),
159135
call('saml_config_signal.slug', signal_saml_slug),
160136
]
@@ -177,7 +153,6 @@ def test_saml_provider_config_updates(self, provider_site_id, provider_slug,
177153
(2, 'slug', 1, 'default'),
178154
)
179155
@ddt.unpack
180-
@override_settings(ENABLE_SAML_CONFIG_SIGNAL_HANDLERS=True)
181156
def test_saml_provider_with_null_config_not_updated(self, provider_site_id, provider_slug,
182157
signal_saml_site_id, signal_saml_slug):
183158
"""

common/djangoapps/third_party_auth/toggles.py

Lines changed: 1 addition & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22
Togglable settings for Third Party Auth
33
"""
44

5-
from edx_toggles.toggles import WaffleFlag, SettingToggle
5+
from edx_toggles.toggles import WaffleFlag
66

77
THIRD_PARTY_AUTH_NAMESPACE = 'thirdpartyauth'
88

@@ -18,26 +18,6 @@
1818
APPLE_USER_MIGRATION_FLAG = WaffleFlag(f'{THIRD_PARTY_AUTH_NAMESPACE}.apple_user_migration', __name__)
1919

2020

21-
# .. toggle_name: ENABLE_SAML_CONFIG_SIGNAL_HANDLERS
22-
# .. toggle_implementation: SettingToggle
23-
# .. toggle_default: False
24-
# .. toggle_description: Controls whether SAML configuration signal handlers are active.
25-
# When enabled (True), signal handlers will automatically update SAMLProviderConfig
26-
# references when the associated SAMLConfiguration is updated.
27-
# When disabled (False), SAMLProviderConfigs point to outdated SAMLConfiguration.
28-
# .. toggle_use_cases: temporary
29-
# .. toggle_creation_date: 2025-07-03
30-
# .. toggle_target_removal_date: 2026-01-01
31-
# .. toggle_warning: Disabling this toggle may result in SAMLProviderConfig instances
32-
# pointing to outdated SAMLConfiguration records. Use the management command
33-
# 'saml --fix-references' to fix outdated references.
34-
ENABLE_SAML_CONFIG_SIGNAL_HANDLERS = SettingToggle(
35-
"ENABLE_SAML_CONFIG_SIGNAL_HANDLERS",
36-
default=False,
37-
module_name=__name__
38-
)
39-
40-
4121
def is_apple_user_migration_enabled():
4222
"""
4323
Returns a boolean if Apple users migration is in process.

0 commit comments

Comments
 (0)