Skip to content
Snippets Groups Projects
Commit 8b65ca17 authored by Uman Shahzad's avatar Uman Shahzad
Browse files

Migrate to latest, split python-social-auth.

PSA was monolothic, now split, with new features, like
a DB-backed partial pipeline. FB OAuth2 version also upped.

Partial pipelines don't get cleared except when necessary.
They persist for special cases like change of browser while
still mid-pipeline (i.e. email validation step).

Refactor, cleanup, and update of a lot of small things as well.

PLEASE NOTE the new `social_auth_partial` table.
parent 4dd4f979
No related merge requests found
Showing
with 138 additions and 118 deletions
......@@ -14,7 +14,7 @@ from django.test import TestCase
from django.test.client import Client
from django.test.utils import override_settings
from mock import patch
from social.apps.django_app.default.models import UserSocialAuth
from social_django.models import UserSocialAuth
from openedx.core.djangoapps.external_auth.models import ExternalAuthMap
from openedx.core.djangolib.testing.utils import CacheIsolationTestCase
......@@ -540,7 +540,6 @@ class LoginOAuthTokenMixin(ThirdPartyOAuthTestMixin):
"""Assert that the given response was a 400 with the given error code"""
self.assertEqual(response.status_code, status_code)
self.assertEqual(json.loads(response.content), {"error": error})
self.assertNotIn("partial_pipeline", self.client.session)
def test_success(self):
self._setup_provider_response(success=True)
......
......@@ -46,9 +46,9 @@ from provider.oauth2.models import Client
from pytz import UTC
from ratelimitbackend.exceptions import RateLimitException
from requests import HTTPError
from social.apps.django_app import utils as social_utils
from social.backends import oauth as social_oauth
from social.exceptions import AuthAlreadyAssociated, AuthException
from social_django import utils as social_utils
from social_core.backends import oauth as social_oauth
from social_core.exceptions import AuthAlreadyAssociated, AuthException
import dogstats_wrapper as dog_stats_api
import openedx.core.djangoapps.external_auth.views
......@@ -1519,7 +1519,7 @@ def login_user(request, error=""): # pylint: disable=too-many-statements,unused
@csrf_exempt
@require_POST
@social_utils.strategy("social:complete")
@social_utils.psa("social:complete")
def login_oauth_token(request, backend):
"""
Authenticate the client using an OAuth access token by using the token to
......@@ -1534,8 +1534,9 @@ def login_oauth_token(request, backend):
# Tell third party auth pipeline that this is an API call
request.session[pipeline.AUTH_ENTRY_KEY] = pipeline.AUTH_ENTRY_LOGIN_API
user = None
access_token = request.POST["access_token"]
try:
user = backend.do_auth(request.POST["access_token"])
user = backend.do_auth(access_token)
except (HTTPError, AuthException):
pass
# do_auth can return a non-User object if it fails
......@@ -1544,7 +1545,7 @@ def login_oauth_token(request, backend):
return JsonResponse(status=204)
else:
# Ensure user does not re-enter the pipeline
request.social_strategy.clean_partial_pipeline()
request.social_strategy.clean_partial_pipeline(access_token)
return JsonResponse({"error": "invalid_token"}, status=401)
else:
return JsonResponse({"error": "invalid_request"}, status=400)
......@@ -1889,7 +1890,7 @@ def create_account_with_params(request, params):
error_message = _("The provided access_token is not valid.")
if not pipeline_user or not isinstance(pipeline_user, User):
# Ensure user does not re-enter the pipeline
request.social_strategy.clean_partial_pipeline()
request.social_strategy.clean_partial_pipeline(social_access_token)
raise ValidationError({'access_token': [error_message]})
# Perform operations that are non-critical parts of account creation
......
......@@ -14,7 +14,7 @@ from openedx.core.lib.api.permissions import ApiKeyHeaderPermission
from rest_framework.test import APITestCase
from django.conf import settings
from django.test.utils import override_settings
from social.apps.django_app.default.models import UserSocialAuth
from social_django.models import UserSocialAuth
from student.tests.factories import UserFactory
from third_party_auth.api.permissions import ThirdPartyAuthProviderApiPermission
......
......@@ -9,7 +9,7 @@ from rest_framework.generics import ListAPIView
from rest_framework.response import Response
from rest_framework.views import APIView
from rest_framework_oauth.authentication import OAuth2Authentication
from social.apps.django_app.default.models import UserSocialAuth
from social_django.models import UserSocialAuth
from openedx.core.lib.api.authentication import (
OAuth2AuthenticationAllowInactiveUser,
......
"""
DummyBackend: A fake Third Party Auth provider for testing & development purposes.
"""
from social.backends.oauth import BaseOAuth2
from social.exceptions import AuthFailed
from social_core.backends.oauth import BaseOAuth2
from social_core.exceptions import AuthFailed
class DummyBackend(BaseOAuth2): # pylint: disable=abstract-method
......
......@@ -14,9 +14,9 @@ from oauthlib.oauth1.rfc5849.signature import (
normalize_parameters,
sign_hmac_sha1
)
from social.backends.base import BaseAuth
from social.exceptions import AuthFailed
from social.utils import sanitize_redirect
from social_core.backends.base import BaseAuth
from social_core.exceptions import AuthFailed
from social_core.utils import sanitize_redirect
log = logging.getLogger(__name__)
......@@ -34,16 +34,13 @@ class LTIAuthBackend(BaseAuth):
"""
Prepare to handle a login request.
This method replaces social.actions.do_auth and must be kept in sync
This method replaces social_core.actions.do_auth and must be kept in sync
with any upstream changes in that method. In the current version of
the upstream, this means replacing the logic to populate the session
from request parameters, and not calling backend.start() to avoid
an unwanted redirect to the non-existent login page.
"""
# Clean any partial pipeline data
self.strategy.clean_partial_pipeline()
# Save validated LTI parameters (or None if invalid or not submitted)
validated_lti_params = self.get_validated_lti_params(self.strategy)
......
"""Middleware classes for third_party_auth."""
from social.apps.django_app.middleware import SocialAuthExceptionMiddleware
from social_django.middleware import SocialAuthExceptionMiddleware
from . import pipeline
......@@ -45,12 +45,10 @@ class PipelineQuarantineMiddleware(object):
collection of user consent for sharing data with a linked third-party
authentication provider.
"""
running_pipeline = request.session.get('partial_pipeline')
if not running_pipeline:
if not pipeline.running(request):
return
view_module = view_func.__module__
quarantined_modules = request.session.get('third_party_auth_quarantined_modules', None)
quarantined_modules = request.session.get('third_party_auth_quarantined_modules')
if quarantined_modules is not None and not any(view_module.startswith(mod) for mod in quarantined_modules):
request.session.flush()
......@@ -17,11 +17,11 @@ from django.utils import timezone
from django.utils.translation import ugettext_lazy as _
from provider.oauth2.models import Client
from provider.utils import long_token
from social.backends.base import BaseAuth
from social.backends.oauth import OAuthAuth
from social.backends.saml import SAMLAuth, SAMLIdentityProvider
from social.exceptions import SocialAuthBaseException
from social.utils import module_member
from social_core.backends.base import BaseAuth
from social_core.backends.oauth import OAuthAuth
from social_core.backends.saml import SAMLAuth, SAMLIdentityProvider
from social_core.exceptions import SocialAuthBaseException
from social_core.utils import module_member
from openedx.core.djangoapps.site_configuration import helpers as configuration_helpers
from openedx.core.djangoapps.theming.helpers import get_current_request
......@@ -581,7 +581,7 @@ class SAMLConfiguration(ConfigurationModel):
return getattr(settings, 'SOCIAL_AUTH_SAML_SP_PRIVATE_KEY', '')
other_config = {
# These defaults can be overriden by self.other_config_str
"EXTRA_DATA": ["attributes"], # Save all attribute values the IdP sends into the UserSocialAuth table
"GET_ALL_EXTRA_DATA": True, # Save all attribute values the IdP sends into the UserSocialAuth table
"TECHNICAL_CONTACT": DEFAULT_SAML_CONTACT,
"SUPPORT_CONTACT": DEFAULT_SAML_CONTACT,
}
......
......@@ -54,7 +54,7 @@ This is surprising but important behavior, since it allows a single function in
the pipeline to consolidate all the operations needed to establish invariants
rather than spreading them across two functions in the pipeline.
See http://psa.matiasaguirre.net/docs/pipeline.html for more docs.
See http://python-social-auth.readthedocs.io/en/latest/pipeline.html for more docs.
"""
import base64
......@@ -73,11 +73,10 @@ from django.contrib.auth.models import User
from django.core.urlresolvers import reverse
from django.http import HttpResponseBadRequest
from django.shortcuts import redirect
from social.apps.django_app.default import models
from social.apps.django_app.default.models import UserSocialAuth
from social.exceptions import AuthException
from social.pipeline import partial
from social.pipeline.social_auth import associate_by_email
import social_django
from social_core.exceptions import AuthException
from social_core.pipeline import partial
from social_core.pipeline.social_auth import associate_by_email
import student
from eventtracking import tracker
......@@ -195,8 +194,14 @@ class ProviderUserState(object):
def get(request):
"""Gets the running pipeline from the passed request."""
return request.session.get('partial_pipeline')
"""Gets the running pipeline's data from the passed request."""
strategy = social_django.utils.load_strategy(request)
token = strategy.session_get('partial_pipeline_token')
partial_object = strategy.partial_load(token)
pipeline_data = None
if partial_object:
pipeline_data = {'kwargs': partial_object.kwargs, 'backend': partial_object.backend}
return pipeline_data
def get_real_social_auth_object(request):
......@@ -209,7 +214,7 @@ def get_real_social_auth_object(request):
if running_pipeline and 'social' in running_pipeline['kwargs']:
social = running_pipeline['kwargs']['social']
if isinstance(social, dict):
social = UserSocialAuth.objects.get(uid=social.get('uid', ''))
social = social_django.models.UserSocialAuth.objects.get(**social)
return social
......@@ -253,7 +258,7 @@ def get_authenticated_user(auth_provider, username, uid):
user has no social auth associated with the given backend.
AssertionError: if the user is not authenticated.
"""
match = models.DjangoStorage.user.get_social_auth(provider=auth_provider.backend_name, uid=uid)
match = social_django.models.DjangoStorage.user.get_social_auth(provider=auth_provider.backend_name, uid=uid)
if not match or match.user.username != username:
raise User.DoesNotExist
......@@ -319,7 +324,7 @@ def get_disconnect_url(provider_id, association_id):
"""Gets URL for the endpoint that starts the disconnect pipeline.
Args:
provider_id: string identifier of the models.ProviderConfig child you want
provider_id: string identifier of the social_django.models.ProviderConfig child you want
to disconnect from.
association_id: int. Optional ID of a specific row in the UserSocialAuth
table to disconnect (useful if multiple providers use a common backend)
......@@ -341,7 +346,7 @@ def get_login_url(provider_id, auth_entry, redirect_url=None):
"""Gets the login URL for the endpoint that kicks off auth with a provider.
Args:
provider_id: string identifier of the models.ProviderConfig child you want
provider_id: string identifier of the social_django.models.ProviderConfig child you want
to disconnect from.
auth_entry: string. Query argument specifying the desired entry point
for the auth pipeline. Used by the pipeline for later branching.
......@@ -404,7 +409,7 @@ def get_provider_user_states(user):
each enabled provider.
"""
states = []
found_user_auths = list(models.DjangoStorage.user.get_social_auth_for_user(user))
found_user_auths = list(social_django.models.DjangoStorage.user.get_social_auth_for_user(user))
for enabled_provider in provider.Registry.enabled():
association = None
......@@ -443,7 +448,7 @@ def make_random_password(length=None, choice_fn=random.SystemRandom().choice):
def running(request):
"""Returns True iff request is running a third-party auth pipeline."""
return request.session.get('partial_pipeline') is not None # Avoid False for {}.
return get(request) is not None # Avoid False for {}.
# Pipeline functions.
......@@ -454,7 +459,7 @@ def running(request):
def parse_query_params(strategy, response, *args, **kwargs):
"""Reads whitelisted query params, transforms them into pipeline args."""
auth_entry = strategy.session.get(AUTH_ENTRY_KEY)
auth_entry = strategy.request.session.get(AUTH_ENTRY_KEY)
if not (auth_entry and auth_entry in _AUTH_ENTRY_CHOICES):
raise AuthEntryError(strategy.request.backend, 'auth_entry missing or invalid')
......@@ -524,7 +529,7 @@ def redirect_to_custom_form(request, auth_entry, kwargs):
@partial.partial
def ensure_user_information(strategy, auth_entry, backend=None, user=None, social=None,
def ensure_user_information(strategy, auth_entry, backend=None, user=None, social=None, current_partial=None,
allow_inactive_user=False, *args, **kwargs):
"""
Ensure that we have the necessary information about a user (either an
......@@ -552,7 +557,7 @@ def ensure_user_information(strategy, auth_entry, backend=None, user=None, socia
def should_force_account_creation():
""" For some third party providers, we auto-create user accounts """
current_provider = provider.Registry.get_from_pipeline({'backend': backend.name, 'kwargs': kwargs})
current_provider = provider.Registry.get_from_pipeline({'backend': current_partial.backend, 'kwargs': kwargs})
return current_provider and current_provider.skip_email_verification
if not user:
......@@ -606,7 +611,8 @@ def ensure_user_information(strategy, auth_entry, backend=None, user=None, socia
@partial.partial
def set_logged_in_cookies(backend=None, user=None, strategy=None, auth_entry=None, *args, **kwargs):
def set_logged_in_cookies(backend=None, user=None, strategy=None, auth_entry=None, current_partial=None,
*args, **kwargs):
"""This pipeline step sets the "logged in" cookie for authenticated users.
Some installations have a marketing site front-end separate from
......@@ -641,7 +647,7 @@ def set_logged_in_cookies(backend=None, user=None, strategy=None, auth_entry=Non
has_cookie = student.cookies.is_logged_in_cookie_set(request)
if not has_cookie:
try:
redirect_url = get_complete_url(backend.name)
redirect_url = get_complete_url(current_partial.backend)
except ValueError:
# If for some reason we can't get the URL, just skip this step
# This may be overly paranoid, but it's far more important that
......@@ -653,7 +659,7 @@ def set_logged_in_cookies(backend=None, user=None, strategy=None, auth_entry=Non
@partial.partial
def login_analytics(strategy, auth_entry, *args, **kwargs):
def login_analytics(strategy, auth_entry, current_partial=None, *args, **kwargs):
""" Sends login info to Segment """
event_name = None
......@@ -682,7 +688,7 @@ def login_analytics(strategy, auth_entry, *args, **kwargs):
@partial.partial
def associate_by_email_if_login_api(auth_entry, backend, details, user, *args, **kwargs):
def associate_by_email_if_login_api(auth_entry, backend, details, user, current_partial=None, *args, **kwargs):
"""
This pipeline step associates the current social auth with the user with the
same email address in the database. It defers to the social library's associate_by_email
......
......@@ -7,8 +7,8 @@ import requests
from django.contrib.sites.models import Site
from django.http import Http404
from django.utils.functional import cached_property
from social.backends.saml import OID_EDU_PERSON_ENTITLEMENT, SAMLAuth, SAMLIdentityProvider
from social.exceptions import AuthForbidden, AuthMissingParameter
from social_core.backends.saml import OID_EDU_PERSON_ENTITLEMENT, SAMLAuth, SAMLIdentityProvider
from social_core.exceptions import AuthForbidden
from openedx.core.djangoapps.theming.helpers import get_current_request
......@@ -43,7 +43,6 @@ class SAMLAuthBackend(SAMLAuth): # pylint: disable=abstract-method
authenticate the user.
raise Http404 if SAML authentication is disabled.
raise AuthMissingParameter if the 'idp' parameter is missing.
"""
if not self._config.enabled:
log.error('SAML authentication is not enabled')
......@@ -70,7 +69,7 @@ class SAMLAuthBackend(SAMLAuth): # pylint: disable=abstract-method
"""
Get an instance of OneLogin_Saml2_Auth
idp: The Identity Provider - a social.backends.saml.SAMLIdentityProvider instance
idp: The Identity Provider - a social_core.backends.saml.SAMLIdentityProvider instance
"""
# We only override this method so that we can add extra debugging when debug_mode is True
# Note that auth_inst is instantiated just for the current HTTP request, then is destroyed
......
......@@ -42,18 +42,18 @@ def apply_settings(django_settings):
# this pipeline.
django_settings.SOCIAL_AUTH_PIPELINE = [
'third_party_auth.pipeline.parse_query_params',
'social.pipeline.social_auth.social_details',
'social.pipeline.social_auth.social_uid',
'social.pipeline.social_auth.auth_allowed',
'social.pipeline.social_auth.social_user',
'social_core.pipeline.social_auth.social_details',
'social_core.pipeline.social_auth.social_uid',
'social_core.pipeline.social_auth.auth_allowed',
'social_core.pipeline.social_auth.social_user',
'third_party_auth.pipeline.associate_by_email_if_login_api',
'social.pipeline.user.get_username',
'social_core.pipeline.user.get_username',
'third_party_auth.pipeline.set_pipeline_timeout',
'third_party_auth.pipeline.ensure_user_information',
'social.pipeline.user.create_user',
'social.pipeline.social_auth.associate_user',
'social.pipeline.social_auth.load_extra_data',
'social.pipeline.user.user_details',
'social_core.pipeline.user.create_user',
'social_core.pipeline.social_auth.associate_user',
'social_core.pipeline.social_auth.load_extra_data',
'social_core.pipeline.user.user_details',
'third_party_auth.pipeline.set_logged_in_cookies',
'third_party_auth.pipeline.login_analytics',
]
......@@ -87,6 +87,6 @@ def apply_settings(django_settings):
# Context processors required under Django.
django_settings.SOCIAL_AUTH_UUID_LENGTH = 4
django_settings.DEFAULT_TEMPLATE_ENGINE['OPTIONS']['context_processors'] += (
'social.apps.django_app.context_processors.backends',
'social.apps.django_app.context_processors.login_redirect',
'social_django.context_processors.backends',
'social_django.context_processors.login_redirect',
)
......@@ -2,8 +2,9 @@
A custom Strategy for python-social-auth that allows us to fetch configuration from
ConfigurationModels rather than django.settings
"""
from social.backends.oauth import OAuthAuth
from social.strategies.django_strategy import DjangoStrategy
from social_core.backends.oauth import OAuthAuth
from social_django.strategy import DjangoStrategy
from .models import OAuth2ProviderConfig
from .pipeline import get as get_pipeline_from_request
......
......@@ -14,9 +14,9 @@ from django.contrib.sessions.backends import cache
from django.core.urlresolvers import reverse
from django.test import utils as django_utils
from django.conf import settings as django_settings
from social import actions, exceptions
from social.apps.django_app import utils as social_utils
from social.apps.django_app import views as social_views
from social_core import actions, exceptions
from social_django import utils as social_utils
from social_django import views as social_views
from lms.djangoapps.commerce.tests import TEST_API_URL
from openedx.core.djangoapps.site_configuration.tests.factories import SiteFactory
......@@ -26,7 +26,6 @@ from student.tests.factories import UserFactory
from student_account.views import account_settings_context
from third_party_auth import middleware, pipeline
from third_party_auth import settings as auth_settings
from third_party_auth.tests import testutil
......@@ -270,7 +269,7 @@ class IntegrationTest(testutil.TestCase, test.TestCase):
form_field_data = self.provider.get_register_form_data(pipeline_kwargs)
for prepopulated_form_data in form_field_data:
if prepopulated_form_data in required_fields:
self.assertIn(form_field_data[prepopulated_form_data], response.content)
self.assertIn(form_field_data[prepopulated_form_data], response.content.decode('utf-8'))
# Implementation details and actual tests past this point -- no more
# configuration needed.
......@@ -285,7 +284,7 @@ class IntegrationTest(testutil.TestCase, test.TestCase):
return self.provider.backend_name
# pylint: disable=invalid-name
def assert_account_settings_context_looks_correct(self, context, _user, duplicate=False, linked=None):
def assert_account_settings_context_looks_correct(self, context, duplicate=False, linked=None):
"""Asserts the user's account settings page context is in the expected state.
If duplicate is True, we expect context['duplicate_provider'] to contain
......@@ -473,7 +472,7 @@ class IntegrationTest(testutil.TestCase, test.TestCase):
return user
def fake_auth_complete(self, strategy):
"""Fake implementation of social.backends.BaseAuth.auth_complete.
"""Fake implementation of social_core.backends.BaseAuth.auth_complete.
Unlike what the docs say, it does not need to return a user instance.
Sometimes (like when directing users to the /register form) it instead
......@@ -515,7 +514,7 @@ class IntegrationTest(testutil.TestCase, test.TestCase):
These two objects contain circular references, so we create them
together. The references themselves are a mixture of normal __init__
stuff and monkey-patching done by python-social-auth. See, for example,
social.apps.django_apps.utils.strategy().
social_django.utils.strategy().
"""
request = self.request_factory.get(
pipeline.get_complete_url(self.backend_name) +
......@@ -600,7 +599,7 @@ class IntegrationTest(testutil.TestCase, test.TestCase):
# First we expect that we're in the unlinked state, and that there
# really is no association in the backend.
self.assert_account_settings_context_looks_correct(account_settings_context(request), request.user, linked=False)
self.assert_account_settings_context_looks_correct(account_settings_context(request), linked=False)
self.assert_social_auth_does_not_exist_for_user(request.user, strategy)
# We should be redirected back to the complete page, setting
......@@ -614,13 +613,19 @@ class IntegrationTest(testutil.TestCase, test.TestCase):
self.set_logged_in_cookies(request)
# Fire off the auth pipeline to link.
self.assert_redirect_to_dashboard_looks_correct(actions.do_complete(
request.backend, social_views._do_login, request.user, None, # pylint: disable=protected-access
redirect_field_name=auth.REDIRECT_FIELD_NAME))
self.assert_redirect_to_dashboard_looks_correct( # pylint: disable=protected-access
actions.do_complete(
request.backend,
social_views._do_login,
request.user,
None,
redirect_field_name=auth.REDIRECT_FIELD_NAME
)
)
# Now we expect to be in the linked state, with a backend entry.
self.assert_social_auth_exists_for_user(request.user, strategy)
self.assert_account_settings_context_looks_correct(account_settings_context(request), request.user, linked=True)
self.assert_account_settings_context_looks_correct(account_settings_context(request), linked=True)
def test_full_pipeline_succeeds_for_unlinking_account(self):
# First, create, the request and strategy that store pipeline state,
......@@ -647,15 +652,21 @@ class IntegrationTest(testutil.TestCase, test.TestCase):
actions.do_complete(request.backend, social_views._do_login, user=user) # pylint: disable=protected-access
# First we expect that we're in the linked state, with a backend entry.
self.assert_account_settings_context_looks_correct(account_settings_context(request), user, linked=True)
self.assert_account_settings_context_looks_correct(account_settings_context(request), linked=True)
self.assert_social_auth_exists_for_user(request.user, strategy)
# Fire off the disconnect pipeline to unlink.
self.assert_redirect_to_dashboard_looks_correct(actions.do_disconnect(
request.backend, request.user, None, redirect_field_name=auth.REDIRECT_FIELD_NAME))
self.assert_redirect_to_dashboard_looks_correct(
actions.do_disconnect(
request.backend,
request.user,
None,
redirect_field_name=auth.REDIRECT_FIELD_NAME
)
)
# Now we expect to be in the unlinked state, with no backend entry.
self.assert_account_settings_context_looks_correct(account_settings_context(request), user, linked=False)
self.assert_account_settings_context_looks_correct(account_settings_context(request), linked=False)
self.assert_social_auth_does_not_exist_for_user(user, strategy)
def test_linking_already_associated_account_raises_auth_already_associated(self):
......@@ -712,7 +723,7 @@ class IntegrationTest(testutil.TestCase, test.TestCase):
exceptions.AuthAlreadyAssociated(self.provider.backend_name, 'account is already in use.'))
self.assert_account_settings_context_looks_correct(
account_settings_context(request), user, duplicate=True, linked=True)
account_settings_context(request), duplicate=True, linked=True)
def test_full_pipeline_succeeds_for_signing_in_to_existing_active_account(self):
# First, create, the request and strategy that store pipeline state,
......@@ -763,7 +774,7 @@ class IntegrationTest(testutil.TestCase, test.TestCase):
self.assert_redirect_to_dashboard_looks_correct(
actions.do_complete(request.backend, social_views._do_login, user=user))
self.assert_account_settings_context_looks_correct(account_settings_context(request), user)
self.assert_account_settings_context_looks_correct(account_settings_context(request))
def test_signin_fails_if_account_not_active(self):
_, strategy = self.get_request_and_strategy(
......@@ -869,7 +880,7 @@ class IntegrationTest(testutil.TestCase, test.TestCase):
actions.do_complete(strategy.request.backend, social_views._do_login, user=created_user))
# Now the user has been redirected to the dashboard. Their third party account should now be linked.
self.assert_social_auth_exists_for_user(created_user, strategy)
self.assert_account_settings_context_looks_correct(account_settings_context(request), created_user, linked=True)
self.assert_account_settings_context_looks_correct(account_settings_context(request), linked=True)
def test_new_account_registration_assigns_distinct_username_on_collision(self):
original_username = self.get_username()
......
......@@ -7,7 +7,7 @@ from third_party_auth.tests import testutil
from .base import IntegrationTestMixin
@unittest.skipUnless(testutil.AUTH_FEATURE_ENABLED, 'third_party_auth not enabled')
@unittest.skipUnless(testutil.AUTH_FEATURE_ENABLED, testutil.AUTH_FEATURES_KEY + ' not enabled')
class GenericIntegrationTest(IntegrationTestMixin, testutil.TestCase):
"""
Basic integration tests of third_party_auth using Dummy provider
......
......@@ -6,7 +6,7 @@ from django.conf import settings
from django.core.urlresolvers import reverse
import json
from mock import patch
from social.exceptions import AuthException
from social_core.exceptions import AuthException
from student.tests.factories import UserFactory
from third_party_auth import pipeline
from third_party_auth.tests.specs import base
......
......@@ -6,10 +6,9 @@ import ddt
import unittest
import httpretty
import json
import time
from mock import patch
from freezegun import freeze_time
from social.apps.django_app.default.models import UserSocialAuth
from social_django.models import UserSocialAuth
from unittest import skip
from third_party_auth.saml import log as saml_log
......@@ -119,7 +118,7 @@ class SamlIntegrationTestUtilities(object):
@ddt.ddt
@unittest.skipUnless(testutil.AUTH_FEATURE_ENABLED, 'third_party_auth not enabled')
@unittest.skipUnless(testutil.AUTH_FEATURE_ENABLED, testutil.AUTH_FEATURES_KEY + ' not enabled')
class TestShibIntegrationTest(SamlIntegrationTestUtilities, IntegrationTestMixin, testutil.SAMLTestCase):
"""
TestShib provider Integration Test, to test SAML functionality
......@@ -157,7 +156,7 @@ class TestShibIntegrationTest(SamlIntegrationTestUtilities, IntegrationTestMixin
record = UserSocialAuth.objects.get(
user=self.user, provider=self.PROVIDER_BACKEND, uid__startswith=self.PROVIDER_IDP_SLUG
)
attributes = record.extra_data["attributes"]
attributes = record.extra_data
self.assertEqual(
attributes.get("urn:oid:1.3.6.1.4.1.5923.1.1.1.9"), ["Member@testshib.org", "Staff@testshib.org"]
)
......@@ -232,7 +231,7 @@ class TestShibIntegrationTest(SamlIntegrationTestUtilities, IntegrationTestMixin
self._test_return_login(previous_session_timed_out=True)
@unittest.skipUnless(testutil.AUTH_FEATURE_ENABLED, 'third_party_auth not enabled')
@unittest.skipUnless(testutil.AUTH_FEATURE_ENABLED, testutil.AUTH_FEATURES_KEY + ' not enabled')
class SuccessFactorsIntegrationTest(SamlIntegrationTestUtilities, IntegrationTestMixin, testutil.SAMLTestCase):
"""
Test basic SAML capability using the TestShib details, and then check that we're able
......
......@@ -20,7 +20,7 @@ class TwitterIntegrationTest(base.Oauth2IntegrationTest):
# To test an OAuth1 provider, we need to patch an additional method:
patcher = patch(
'social.backends.twitter.TwitterOAuth.unauthorized_token',
'social_core.backends.twitter.TwitterOAuth.unauthorized_token',
create=True,
return_value="unauth_token"
)
......
......@@ -16,7 +16,7 @@ from third_party_auth.tests import testutil
# This is necessary because cms does not implement third party auth
@unittest.skipUnless(settings.FEATURES.get('ENABLE_THIRD_PARTY_AUTH'), 'third party auth not enabled')
@unittest.skipUnless(testutil.AUTH_FEATURE_ENABLED, testutil.AUTH_FEATURES_KEY + ' not enabled')
class Oauth2ProviderConfigAdminTest(testutil.TestCase):
"""
Tests for oauth2 provider config admin
......
......@@ -5,6 +5,7 @@ import unittest
from django.conf import settings
from django.test import Client
from social_django.models import Partial
@unittest.skipUnless(settings.ROOT_URLCONF == 'lms.urls', 'Test only valid in lms')
......@@ -13,39 +14,47 @@ class TestSessionFlushMiddleware(unittest.TestCase):
Ensure that if the pipeline is exited when it's been quarantined,
the entire session is flushed.
"""
def setUp(self):
self.client = Client()
self.fancy_variable = 13025
self.token = 'pipeline_running'
self.tpa_quarantined_modules = ('fake_quarantined_module',)
def tearDown(self):
Partial.objects.all().delete()
def test_session_flush(self):
"""
Test that a quarantined session is flushed when navigating elsewhere
"""
client = Client()
session = client.session
session['fancy_variable'] = 13025
session['partial_pipeline'] = 'pipeline_running'
session['third_party_auth_quarantined_modules'] = ('fake_quarantined_module',)
session = self.client.session
session['fancy_variable'] = self.fancy_variable
session['partial_pipeline_token'] = self.token
session['third_party_auth_quarantined_modules'] = self.tpa_quarantined_modules
session.save()
client.get('/')
self.assertEqual(client.session.get('fancy_variable', None), None)
Partial.objects.create(token=session.get('partial_pipeline_token'))
self.client.get('/')
self.assertEqual(self.client.session.get('fancy_variable', None), None)
def test_session_no_running_pipeline(self):
"""
Test that a quarantined session without a running pipeline is not flushed
"""
client = Client()
session = client.session
session['fancy_variable'] = 13025
session['third_party_auth_quarantined_modules'] = ('fake_quarantined_module',)
session = self.client.session
session['fancy_variable'] = self.fancy_variable
session['third_party_auth_quarantined_modules'] = self.tpa_quarantined_modules
session.save()
client.get('/')
self.assertEqual(client.session.get('fancy_variable', None), 13025)
self.client.get('/')
self.assertEqual(self.client.session.get('fancy_variable', None), self.fancy_variable)
def test_session_no_quarantine(self):
"""
Test that a session with a running pipeline but no quarantine is not flushed
"""
client = Client()
session = client.session
session['fancy_variable'] = 13025
session['partial_pipeline'] = 'pipeline_running'
session = self.client.session
session['fancy_variable'] = self.fancy_variable
session['partial_pipeline_token'] = self.token
session.save()
client.get('/')
self.assertEqual(client.session.get('fancy_variable', None), 13025)
Partial.objects.create(token=session.get('partial_pipeline_token'))
self.client.get('/')
self.assertEqual(self.client.session.get('fancy_variable', None), self.fancy_variable)
......@@ -35,7 +35,7 @@ class MakeRandomPasswordTest(testutil.TestCase):
self.assertEqual(expected, pipeline.make_random_password(choice_fn=random_instance.choice))
@unittest.skipUnless(testutil.AUTH_FEATURE_ENABLED, 'third_party_auth not enabled')
@unittest.skipUnless(testutil.AUTH_FEATURE_ENABLED, testutil.AUTH_FEATURES_KEY + ' not enabled')
class ProviderUserStateTestCase(testutil.TestCase):
"""Tests ProviderUserState behavior."""
......
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment