From be4b676604fff170bd6affbe24a36c584d4fe187 Mon Sep 17 00:00:00 2001 From: Navin Karkera Date: Mon, 19 Jun 2023 12:54:46 +0530 Subject: [PATCH 1/3] feat: allow oauth configuration per site and backend Allows admins to configure same oauth backend for multiple sites --- .../third_party_auth/api/tests/test_views.py | 4 ++-- common/djangoapps/third_party_auth/models.py | 19 +++++++++++++++- .../tests/specs/test_google.py | 4 ++-- .../third_party_auth/tests/test_provider.py | 13 ++++++++--- .../user_authn/api/tests/test_views.py | 4 ++-- .../views/tests/test_logistration.py | 22 +++++++++---------- 6 files changed, 45 insertions(+), 21 deletions(-) diff --git a/common/djangoapps/third_party_auth/api/tests/test_views.py b/common/djangoapps/third_party_auth/api/tests/test_views.py index ce6da78c6b09..72e499648c43 100644 --- a/common/djangoapps/third_party_auth/api/tests/test_views.py +++ b/common/djangoapps/third_party_auth/api/tests/test_views.py @@ -97,7 +97,7 @@ def expected_active(self, username): return [] return [ { - "provider_id": "oa2-google-oauth2", + "provider_id": "oa2-1-google-oauth2", "name": "Google", "remote_id": f"{username}@gmail.com", }, @@ -380,5 +380,5 @@ def test_get(self): 'accepts_logins': True, 'name': 'Google', 'disconnect_url': '/auth/disconnect/google-oauth2/?', 'connect_url': '/auth/login/google-oauth2/?auth_entry=account_settings&next=%2Faccount%2Fsettings', - 'connected': False, 'id': 'oa2-google-oauth2' + 'connected': False, 'id': 'oa2-1-google-oauth2' }]) diff --git a/common/djangoapps/third_party_auth/models.py b/common/djangoapps/third_party_auth/models.py index f0a37616a3d1..0224bde52fa5 100644 --- a/common/djangoapps/third_party_auth/models.py +++ b/common/djangoapps/third_party_auth/models.py @@ -367,7 +367,7 @@ class OAuth2ProviderConfig(ProviderConfig): # example: # class SecondOpenIDProvider(OpenIDAuth): # name = "second-openId-provider" - KEY_FIELDS = ('backend_name',) + KEY_FIELDS = ('site_id', 'backend_name') prefix = 'oa2' backend_name = models.CharField( max_length=50, blank=False, db_index=True, @@ -396,6 +396,23 @@ class Meta: verbose_name = "Provider Configuration (OAuth)" verbose_name_plural = verbose_name + @classmethod + def current(cls, *args): + """ + Get the current config model for the provider according to the given backend and the current + site. + """ + site_id = Site.objects.get_current(get_current_request()).id + return super(OAuth2ProviderConfig, cls).current(site_id, *args) + + @property + def provider_id(self): + """ + Unique string key identifying this provider. Must be URL and css class friendly. + """ + assert self.prefix is not None + return "-".join((self.prefix, ) + tuple(str(getattr(self, field)) for field in self.KEY_FIELDS)) + def clean(self): """ Standardize and validate fields """ super().clean() diff --git a/common/djangoapps/third_party_auth/tests/specs/test_google.py b/common/djangoapps/third_party_auth/tests/specs/test_google.py index 0592f50734a7..54ec11a603ac 100644 --- a/common/djangoapps/third_party_auth/tests/specs/test_google.py +++ b/common/djangoapps/third_party_auth/tests/specs/test_google.py @@ -21,7 +21,7 @@ class GoogleOauth2IntegrationTest(base.Oauth2IntegrationTest): # lint-amnesty, PROVIDER_NAME = "google" PROVIDER_BACKEND = "google-oauth2" - PROVIDER_ID = "oa2-google-oauth2" + PROVIDER_ID = "oa2-1-google-oauth2" def setUp(self): super().setUp() @@ -89,7 +89,7 @@ def fake_auth_complete(inst, *args, **kwargs): data_parsed = json.loads(data_decoded) # The user's details get passed to the custom page as a base64 encoded query parameter: assert data_parsed == {'auth_entry': 'custom1', 'backend_name': 'google-oauth2', - 'provider_id': 'oa2-google-oauth2', + 'provider_id': 'oa2-1-google-oauth2', 'user_details': {'username': 'user', 'email': 'user@email.com', 'fullname': 'name_value', 'first_name': 'given_name_value', 'last_name': 'family_name_value'}} diff --git a/common/djangoapps/third_party_auth/tests/test_provider.py b/common/djangoapps/third_party_auth/tests/test_provider.py index 99a8d545a4f7..41b9e4ffb261 100644 --- a/common/djangoapps/third_party_auth/tests/test_provider.py +++ b/common/djangoapps/third_party_auth/tests/test_provider.py @@ -114,7 +114,7 @@ def test_providers_displayed_for_login(self): assert no_log_in_provider.provider_id not in provider_ids assert normal_provider.provider_id in provider_ids - def test_tpa_hint_provider_displayed_for_login(self): + def test_tpa_hint_hidden_provider_displayed_for_login(self): """ Tests to ensure that an enabled-but-not-visible provider is presented for use in the UI when the "tpa_hint" parameter is specified @@ -128,6 +128,7 @@ def test_tpa_hint_provider_displayed_for_login(self): ] assert hidden_provider.provider_id in provider_ids + def test_tpa_hint_exp_hidden_provider_displayed_for_login(self): # New providers are hidden (ie, not flagged as 'visible') by default # The tpa_hint parameter should work for these providers as well implicitly_hidden_provider = self.configure_linkedin_provider(enabled=True) @@ -137,6 +138,7 @@ def test_tpa_hint_provider_displayed_for_login(self): ] assert implicitly_hidden_provider.provider_id in provider_ids + def test_tpa_hint_disabled_hidden_provider_displayed_for_login(self): # Disabled providers should not be matched in tpa_hint scenarios disabled_provider = self.configure_twitter_provider(visible=True, enabled=False) provider_ids = [ @@ -145,6 +147,7 @@ def test_tpa_hint_provider_displayed_for_login(self): ] assert disabled_provider.provider_id not in provider_ids + def test_tpa_hint_no_log_hidden_provider_displayed_for_login(self): # Providers not utilized for learner authentication should not match tpa_hint no_log_in_provider = self.configure_lti_provider() provider_ids = [ @@ -201,14 +204,18 @@ def test_oauth2_enabled_only_for_supplied_backend(self): def test_get_returns_none_if_provider_id_is_none(self): assert provider.Registry.get(None) is None - def test_get_returns_none_if_provider_not_enabled(self): - linkedin_provider_id = "oa2-linkedin-oauth2" + def test_get_returns_none_if_provider_not_enabled_change(self): + linkedin_provider_id = "oa2-1-linkedin-oauth2" # At this point there should be no configuration entries at all so no providers should be enabled assert provider.Registry.enabled() == [] assert provider.Registry.get(linkedin_provider_id) is None # Now explicitly disabled this provider: self.configure_linkedin_provider(enabled=False) assert provider.Registry.get(linkedin_provider_id) is None + + def test_get_returns_provider_if_provider_enabled(self): + """Test to ensure that Registry gets enabled providers.""" + linkedin_provider_id = "oa2-1-linkedin-oauth2" self.configure_linkedin_provider(enabled=True) assert provider.Registry.get(linkedin_provider_id).provider_id == linkedin_provider_id diff --git a/openedx/core/djangoapps/user_authn/api/tests/test_views.py b/openedx/core/djangoapps/user_authn/api/tests/test_views.py index efa16168f671..2c0b41f28317 100644 --- a/openedx/core/djangoapps/user_authn/api/tests/test_views.py +++ b/openedx/core/djangoapps/user_authn/api/tests/test_views.py @@ -63,7 +63,7 @@ def get_provider_data(self, params): """ return [ { - 'id': 'oa2-facebook', + 'id': 'oa2-1-facebook', 'name': 'Facebook', 'iconClass': 'fa-facebook', 'iconImage': None, @@ -72,7 +72,7 @@ def get_provider_data(self, params): 'registerUrl': self._third_party_login_url('facebook', 'register', params) }, { - 'id': 'oa2-google-oauth2', + 'id': 'oa2-1-google-oauth2', 'name': 'Google', 'iconClass': 'fa-google-plus', 'iconImage': None, diff --git a/openedx/core/djangoapps/user_authn/views/tests/test_logistration.py b/openedx/core/djangoapps/user_authn/views/tests/test_logistration.py index b92fdbefb43b..4a34f24c218c 100644 --- a/openedx/core/djangoapps/user_authn/views/tests/test_logistration.py +++ b/openedx/core/djangoapps/user_authn/views/tests/test_logistration.py @@ -286,7 +286,7 @@ def test_third_party_auth( # This relies on the THIRD_PARTY_AUTH configuration in the test settings expected_providers = [ { - "id": "oa2-dummy", + "id": "oa2-1-dummy", "name": "Dummy", "iconClass": None, "iconImage": settings.MEDIA_URL + "icon.svg", @@ -295,7 +295,7 @@ def test_third_party_auth( "registerUrl": self._third_party_login_url("dummy", "register", params) }, { - "id": "oa2-facebook", + "id": "oa2-1-facebook", "name": "Facebook", "iconClass": "fa-facebook", "iconImage": None, @@ -304,7 +304,7 @@ def test_third_party_auth( "registerUrl": self._third_party_login_url("facebook", "register", params) }, { - "id": "oa2-google-oauth2", + "id": "oa2-1-google-oauth2", "name": "Google", "iconClass": "fa-google-plus", "iconImage": None, @@ -406,9 +406,9 @@ def test_saml_auth_with_error( ) def test_hinted_login(self): - params = [("next", "/courses/something/?tpa_hint=oa2-google-oauth2")] + params = [("next", "/courses/something/?tpa_hint=oa2-1-google-oauth2")] response = self.client.get(reverse('signin_user'), params, HTTP_ACCEPT="text/html") - self.assertContains(response, '"third_party_auth_hint": "oa2-google-oauth2"') + self.assertContains(response, '"third_party_auth_hint": "oa2-1-google-oauth2"') tpa_hint = self.hidden_enabled_provider.provider_id params = [("next", f"/courses/something/?tpa_hint={tpa_hint}")] @@ -429,17 +429,17 @@ def test_hinted_login_dialog_disabled(self, url_name, auth_entry): """Test that the dialog doesn't show up for hinted logins when disabled. """ self.google_provider.skip_hinted_login_dialog = True self.google_provider.save() - params = [("next", "/courses/something/?tpa_hint=oa2-google-oauth2")] + params = [("next", "/courses/something/?tpa_hint=oa2-1-google-oauth2")] response = self.client.get(reverse(url_name), params, HTTP_ACCEPT="text/html") expected_url = '/auth/login/google-oauth2/?auth_entry={}&next=%2Fcourses'\ - '%2Fsomething%2F%3Ftpa_hint%3Doa2-google-oauth2'.format(auth_entry) + '%2Fsomething%2F%3Ftpa_hint%3Doa2-1-google-oauth2'.format(auth_entry) self.assertRedirects( response, expected_url, target_status_code=302 ) - @override_settings(FEATURES=dict(settings.FEATURES, THIRD_PARTY_AUTH_HINT='oa2-google-oauth2')) + @override_settings(FEATURES=dict(settings.FEATURES, THIRD_PARTY_AUTH_HINT='oa2-1-google-oauth2')) @ddt.data( 'signin_user', 'register_user', @@ -450,7 +450,7 @@ def test_settings_tpa_hinted_login(self, url_name): """ params = [("next", "/courses/something/")] response = self.client.get(reverse(url_name), params, HTTP_ACCEPT="text/html") - self.assertContains(response, '"third_party_auth_hint": "oa2-google-oauth2"') + self.assertContains(response, '"third_party_auth_hint": "oa2-1-google-oauth2"') # THIRD_PARTY_AUTH_HINT can be overridden via the query string tpa_hint = self.hidden_enabled_provider.provider_id @@ -464,7 +464,7 @@ def test_settings_tpa_hinted_login(self, url_name): response = self.client.get(reverse(url_name), params, HTTP_ACCEPT="text/html") assert response.content.decode('utf-8') not in tpa_hint - @override_settings(FEATURES=dict(settings.FEATURES, THIRD_PARTY_AUTH_HINT='oa2-google-oauth2')) + @override_settings(FEATURES=dict(settings.FEATURES, THIRD_PARTY_AUTH_HINT='oa2-1-google-oauth2')) @ddt.data( ('signin_user', 'login'), ('register_user', 'register'), @@ -477,7 +477,7 @@ def test_settings_tpa_hinted_login_dialog_disabled(self, url_name, auth_entry): params = [("next", "/courses/something/")] response = self.client.get(reverse(url_name), params, HTTP_ACCEPT="text/html") expected_url = '/auth/login/google-oauth2/?auth_entry={}&next=%2Fcourses'\ - '%2Fsomething%2F%3Ftpa_hint%3Doa2-google-oauth2'.format(auth_entry) + '%2Fsomething%2F%3Ftpa_hint%3Doa2-1-google-oauth2'.format(auth_entry) self.assertRedirects( response, expected_url, From ec738bc1f137409f62cbb424cacb58912a8c86e3 Mon Sep 17 00:00:00 2001 From: Navin Karkera Date: Thu, 22 Jun 2023 12:24:15 +0530 Subject: [PATCH 2/3] fix: skip pipeline if oauth provider for site is not setup --- common/djangoapps/third_party_auth/pipeline.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/common/djangoapps/third_party_auth/pipeline.py b/common/djangoapps/third_party_auth/pipeline.py index cc931df4ece1..b53af59de678 100644 --- a/common/djangoapps/third_party_auth/pipeline.py +++ b/common/djangoapps/third_party_auth/pipeline.py @@ -854,7 +854,7 @@ def user_details_force_sync(auth_entry, strategy, details, user=None, *args, **k This step is controlled by the `sync_learner_profile_data` flag on the provider's configuration. """ current_provider = provider.Registry.get_from_pipeline({'backend': strategy.request.backend.name, 'kwargs': kwargs}) - if user and current_provider.sync_learner_profile_data: + if user and current_provider and current_provider.sync_learner_profile_data: # Keep track of which incoming values get applied. changed = {} @@ -931,7 +931,7 @@ def set_id_verification_status(auth_entry, strategy, details, user=None, *args, Use the user's authentication with the provider, if configured, as evidence of their identity being verified. """ current_provider = provider.Registry.get_from_pipeline({'backend': strategy.request.backend.name, 'kwargs': kwargs}) - if user and current_provider.enable_sso_id_verification: + if user and current_provider and current_provider.enable_sso_id_verification: # Get previous valid, non expired verification attempts for this SSO Provider and user verifications = SSOVerification.objects.filter( user=user, From 7bbe8e8feea43fa2ed9c941045f03e2eff8b4482 Mon Sep 17 00:00:00 2001 From: Navin Karkera Date: Thu, 6 Jul 2023 11:56:49 +0530 Subject: [PATCH 3/3] refactor: remove site_id from provider_id --- .../third_party_auth/api/tests/test_views.py | 4 ++-- common/djangoapps/third_party_auth/models.py | 13 +++++++---- .../tests/specs/test_google.py | 4 ++-- .../third_party_auth/tests/test_provider.py | 4 ++-- .../user_authn/api/tests/test_views.py | 4 ++-- .../views/tests/test_logistration.py | 22 +++++++++---------- 6 files changed, 28 insertions(+), 23 deletions(-) diff --git a/common/djangoapps/third_party_auth/api/tests/test_views.py b/common/djangoapps/third_party_auth/api/tests/test_views.py index 72e499648c43..ce6da78c6b09 100644 --- a/common/djangoapps/third_party_auth/api/tests/test_views.py +++ b/common/djangoapps/third_party_auth/api/tests/test_views.py @@ -97,7 +97,7 @@ def expected_active(self, username): return [] return [ { - "provider_id": "oa2-1-google-oauth2", + "provider_id": "oa2-google-oauth2", "name": "Google", "remote_id": f"{username}@gmail.com", }, @@ -380,5 +380,5 @@ def test_get(self): 'accepts_logins': True, 'name': 'Google', 'disconnect_url': '/auth/disconnect/google-oauth2/?', 'connect_url': '/auth/login/google-oauth2/?auth_entry=account_settings&next=%2Faccount%2Fsettings', - 'connected': False, 'id': 'oa2-1-google-oauth2' + 'connected': False, 'id': 'oa2-google-oauth2' }]) diff --git a/common/djangoapps/third_party_auth/models.py b/common/djangoapps/third_party_auth/models.py index 0224bde52fa5..5772b846a3dc 100644 --- a/common/djangoapps/third_party_auth/models.py +++ b/common/djangoapps/third_party_auth/models.py @@ -361,9 +361,8 @@ class OAuth2ProviderConfig(ProviderConfig): .. no_pii: """ - # We are keying the provider config by backend_name here as suggested in the python social - # auth documentation. In order to reuse a backend for a second provider, a subclass can be - # created with seperate name. + # We are keying the provider config by backend_name and site_id to support configuration per site. + # In order to reuse a backend for a second provider, a subclass can be created with seperate name. # example: # class SecondOpenIDProvider(OpenIDAuth): # name = "second-openId-provider" @@ -409,9 +408,15 @@ def current(cls, *args): def provider_id(self): """ Unique string key identifying this provider. Must be URL and css class friendly. + Ignoring site_id as the config is filtered using current method which fetches the configuration for the current + site_id. """ assert self.prefix is not None - return "-".join((self.prefix, ) + tuple(str(getattr(self, field)) for field in self.KEY_FIELDS)) + return "-".join((self.prefix, ) + tuple( + str(getattr(self, field)) + for field in self.KEY_FIELDS + if field != 'site_id' + )) def clean(self): """ Standardize and validate fields """ diff --git a/common/djangoapps/third_party_auth/tests/specs/test_google.py b/common/djangoapps/third_party_auth/tests/specs/test_google.py index 54ec11a603ac..0592f50734a7 100644 --- a/common/djangoapps/third_party_auth/tests/specs/test_google.py +++ b/common/djangoapps/third_party_auth/tests/specs/test_google.py @@ -21,7 +21,7 @@ class GoogleOauth2IntegrationTest(base.Oauth2IntegrationTest): # lint-amnesty, PROVIDER_NAME = "google" PROVIDER_BACKEND = "google-oauth2" - PROVIDER_ID = "oa2-1-google-oauth2" + PROVIDER_ID = "oa2-google-oauth2" def setUp(self): super().setUp() @@ -89,7 +89,7 @@ def fake_auth_complete(inst, *args, **kwargs): data_parsed = json.loads(data_decoded) # The user's details get passed to the custom page as a base64 encoded query parameter: assert data_parsed == {'auth_entry': 'custom1', 'backend_name': 'google-oauth2', - 'provider_id': 'oa2-1-google-oauth2', + 'provider_id': 'oa2-google-oauth2', 'user_details': {'username': 'user', 'email': 'user@email.com', 'fullname': 'name_value', 'first_name': 'given_name_value', 'last_name': 'family_name_value'}} diff --git a/common/djangoapps/third_party_auth/tests/test_provider.py b/common/djangoapps/third_party_auth/tests/test_provider.py index 41b9e4ffb261..21c3de03a620 100644 --- a/common/djangoapps/third_party_auth/tests/test_provider.py +++ b/common/djangoapps/third_party_auth/tests/test_provider.py @@ -205,7 +205,7 @@ def test_get_returns_none_if_provider_id_is_none(self): assert provider.Registry.get(None) is None def test_get_returns_none_if_provider_not_enabled_change(self): - linkedin_provider_id = "oa2-1-linkedin-oauth2" + linkedin_provider_id = "oa2-linkedin-oauth2" # At this point there should be no configuration entries at all so no providers should be enabled assert provider.Registry.enabled() == [] assert provider.Registry.get(linkedin_provider_id) is None @@ -215,7 +215,7 @@ def test_get_returns_none_if_provider_not_enabled_change(self): def test_get_returns_provider_if_provider_enabled(self): """Test to ensure that Registry gets enabled providers.""" - linkedin_provider_id = "oa2-1-linkedin-oauth2" + linkedin_provider_id = "oa2-linkedin-oauth2" self.configure_linkedin_provider(enabled=True) assert provider.Registry.get(linkedin_provider_id).provider_id == linkedin_provider_id diff --git a/openedx/core/djangoapps/user_authn/api/tests/test_views.py b/openedx/core/djangoapps/user_authn/api/tests/test_views.py index 2c0b41f28317..efa16168f671 100644 --- a/openedx/core/djangoapps/user_authn/api/tests/test_views.py +++ b/openedx/core/djangoapps/user_authn/api/tests/test_views.py @@ -63,7 +63,7 @@ def get_provider_data(self, params): """ return [ { - 'id': 'oa2-1-facebook', + 'id': 'oa2-facebook', 'name': 'Facebook', 'iconClass': 'fa-facebook', 'iconImage': None, @@ -72,7 +72,7 @@ def get_provider_data(self, params): 'registerUrl': self._third_party_login_url('facebook', 'register', params) }, { - 'id': 'oa2-1-google-oauth2', + 'id': 'oa2-google-oauth2', 'name': 'Google', 'iconClass': 'fa-google-plus', 'iconImage': None, diff --git a/openedx/core/djangoapps/user_authn/views/tests/test_logistration.py b/openedx/core/djangoapps/user_authn/views/tests/test_logistration.py index 4a34f24c218c..b92fdbefb43b 100644 --- a/openedx/core/djangoapps/user_authn/views/tests/test_logistration.py +++ b/openedx/core/djangoapps/user_authn/views/tests/test_logistration.py @@ -286,7 +286,7 @@ def test_third_party_auth( # This relies on the THIRD_PARTY_AUTH configuration in the test settings expected_providers = [ { - "id": "oa2-1-dummy", + "id": "oa2-dummy", "name": "Dummy", "iconClass": None, "iconImage": settings.MEDIA_URL + "icon.svg", @@ -295,7 +295,7 @@ def test_third_party_auth( "registerUrl": self._third_party_login_url("dummy", "register", params) }, { - "id": "oa2-1-facebook", + "id": "oa2-facebook", "name": "Facebook", "iconClass": "fa-facebook", "iconImage": None, @@ -304,7 +304,7 @@ def test_third_party_auth( "registerUrl": self._third_party_login_url("facebook", "register", params) }, { - "id": "oa2-1-google-oauth2", + "id": "oa2-google-oauth2", "name": "Google", "iconClass": "fa-google-plus", "iconImage": None, @@ -406,9 +406,9 @@ def test_saml_auth_with_error( ) def test_hinted_login(self): - params = [("next", "/courses/something/?tpa_hint=oa2-1-google-oauth2")] + params = [("next", "/courses/something/?tpa_hint=oa2-google-oauth2")] response = self.client.get(reverse('signin_user'), params, HTTP_ACCEPT="text/html") - self.assertContains(response, '"third_party_auth_hint": "oa2-1-google-oauth2"') + self.assertContains(response, '"third_party_auth_hint": "oa2-google-oauth2"') tpa_hint = self.hidden_enabled_provider.provider_id params = [("next", f"/courses/something/?tpa_hint={tpa_hint}")] @@ -429,17 +429,17 @@ def test_hinted_login_dialog_disabled(self, url_name, auth_entry): """Test that the dialog doesn't show up for hinted logins when disabled. """ self.google_provider.skip_hinted_login_dialog = True self.google_provider.save() - params = [("next", "/courses/something/?tpa_hint=oa2-1-google-oauth2")] + params = [("next", "/courses/something/?tpa_hint=oa2-google-oauth2")] response = self.client.get(reverse(url_name), params, HTTP_ACCEPT="text/html") expected_url = '/auth/login/google-oauth2/?auth_entry={}&next=%2Fcourses'\ - '%2Fsomething%2F%3Ftpa_hint%3Doa2-1-google-oauth2'.format(auth_entry) + '%2Fsomething%2F%3Ftpa_hint%3Doa2-google-oauth2'.format(auth_entry) self.assertRedirects( response, expected_url, target_status_code=302 ) - @override_settings(FEATURES=dict(settings.FEATURES, THIRD_PARTY_AUTH_HINT='oa2-1-google-oauth2')) + @override_settings(FEATURES=dict(settings.FEATURES, THIRD_PARTY_AUTH_HINT='oa2-google-oauth2')) @ddt.data( 'signin_user', 'register_user', @@ -450,7 +450,7 @@ def test_settings_tpa_hinted_login(self, url_name): """ params = [("next", "/courses/something/")] response = self.client.get(reverse(url_name), params, HTTP_ACCEPT="text/html") - self.assertContains(response, '"third_party_auth_hint": "oa2-1-google-oauth2"') + self.assertContains(response, '"third_party_auth_hint": "oa2-google-oauth2"') # THIRD_PARTY_AUTH_HINT can be overridden via the query string tpa_hint = self.hidden_enabled_provider.provider_id @@ -464,7 +464,7 @@ def test_settings_tpa_hinted_login(self, url_name): response = self.client.get(reverse(url_name), params, HTTP_ACCEPT="text/html") assert response.content.decode('utf-8') not in tpa_hint - @override_settings(FEATURES=dict(settings.FEATURES, THIRD_PARTY_AUTH_HINT='oa2-1-google-oauth2')) + @override_settings(FEATURES=dict(settings.FEATURES, THIRD_PARTY_AUTH_HINT='oa2-google-oauth2')) @ddt.data( ('signin_user', 'login'), ('register_user', 'register'), @@ -477,7 +477,7 @@ def test_settings_tpa_hinted_login_dialog_disabled(self, url_name, auth_entry): params = [("next", "/courses/something/")] response = self.client.get(reverse(url_name), params, HTTP_ACCEPT="text/html") expected_url = '/auth/login/google-oauth2/?auth_entry={}&next=%2Fcourses'\ - '%2Fsomething%2F%3Ftpa_hint%3Doa2-1-google-oauth2'.format(auth_entry) + '%2Fsomething%2F%3Ftpa_hint%3Doa2-google-oauth2'.format(auth_entry) self.assertRedirects( response, expected_url,