diff --git a/common/djangoapps/third_party_auth/pipeline.py b/common/djangoapps/third_party_auth/pipeline.py index 418f0b7167..97e496a775 100644 --- a/common/djangoapps/third_party_auth/pipeline.py +++ b/common/djangoapps/third_party_auth/pipeline.py @@ -151,19 +151,6 @@ class AuthEntryError(AuthException): """ -class NotActivatedException(AuthException): - """ Raised when a user tries to login to an unverified account """ - def __init__(self, backend, email): - self.email = email - super(NotActivatedException, self).__init__(backend, email) - - def __str__(self): - return ( - _('This account has not yet been activated. An activation email has been re-sent to {email_address}.') - .format(email_address=self.email) - ) - - class ProviderUserState(object): """Object representing the provider state (attached or not) for a user. @@ -514,26 +501,24 @@ def ensure_user_information(strategy, auth_entry, backend=None, user=None, socia # This parameter is used by the auth_exchange app, which always allows users to # login, whether or not their account is validated. pass - # IF the user has just registered a new account as part of this pipeline, that is fine - # and we allow the login to continue this once, because if we pause again to force the - # user to activate their account via email, the pipeline may get lost (e.g. email takes - # too long to arrive, user opens the activation email on a different device, etc.). - # This is consistent with first party auth and ensures that the pipeline completes - # fully, which is critical. - # But if this is an existing account, we refuse to allow them to login again until they - # check their email and activate the account. - elif social is not None: - # This third party account is already linked to a user account. That means that the - # user's account existed before this pipeline originally began (since the creation - # of the 'social' link entry occurs in one of the following pipeline steps). - # Reject this login attempt and tell the user to validate their account first. - - # Send them another activation email: - student.views.reactivation_email_for_user(user) - - raise NotActivatedException(backend, user.email) - # else: The user must have just successfully registered their account, so we proceed. - # We know they did not just login, because the login process rejects unverified users. + elif social is None: + # The user has just registered a new account as part of this pipeline. Their account + # is inactive but we allow the login to continue, because if we pause again to force + # the user to activate their account via email, the pipeline may get lost (e.g. + # email takes too long to arrive, user opens the activation email on a different + # device, etc.). This is consistent with first party auth and ensures that the + # pipeline completes fully, which is critical. + pass + else: + # This is an existing account, linked to a third party provider but not activated. + # We now also allow them to login again, because if they had entered their email + # incorrectly then there would be no way for them to recover the account, nor + # register anew via SSO. See SOL-1324 in JIRA. + # However, we will log a warning for this case: + logger.warning( + 'User "%s" is using third_party_auth to login but has not yet activated their account. ', + user.username + ) @partial.partial diff --git a/common/djangoapps/third_party_auth/settings.py b/common/djangoapps/third_party_auth/settings.py index a856aefa4f..fd9fa7abf9 100644 --- a/common/djangoapps/third_party_auth/settings.py +++ b/common/djangoapps/third_party_auth/settings.py @@ -73,11 +73,10 @@ def apply_settings(django_settings): django_settings.SOCIAL_AUTH_RAISE_EXCEPTIONS = False # Allow users to login using social auth even if their account is not verified yet - # The 'ensure_user_information' step controls this and only allows brand new users - # to login without verification. Repeat logins are not permitted until the account - # gets verified. - django_settings.INACTIVE_USER_LOGIN = True - django_settings.INACTIVE_USER_URL = '/auth/inactive' + # Otherwise users who use social auth to register with an invalid email address + # can become "stuck". We control this in a more fine-grained manner in pipeline.py + django_settings.SOCIAL_AUTH_INACTIVE_USER_LOGIN = True + django_settings.SOCIAL_AUTH_INACTIVE_USER_URL = '/auth/inactive' # Context processors required under Django. django_settings.SOCIAL_AUTH_UUID_LENGTH = 4 diff --git a/common/djangoapps/third_party_auth/views.py b/common/djangoapps/third_party_auth/views.py index 58fd17c784..daa104383b 100644 --- a/common/djangoapps/third_party_auth/views.py +++ b/common/djangoapps/third_party_auth/views.py @@ -17,8 +17,13 @@ URL_NAMESPACE = getattr(settings, setting_name('URL_NAMESPACE'), None) or 'socia def inactive_user_view(request): """ - A newly registered user has completed the social auth pipeline. - Their account is not yet activated, but we let them login this once. + A newly or recently registered user has completed the social auth pipeline. + Their account is not yet activated, but we let them login since the third party auth + provider is trusted to vouch for them. See details in pipeline.py. + + The reason this view exists is that if we don't define this as the + SOCIAL_AUTH_INACTIVE_USER_URL, inactive users will get sent to LOGIN_ERROR_URL, which we + don't want. """ # 'next' may be set to '/account/finish_auth/.../' if this user needs to be auto-enrolled # in a course. Otherwise, just redirect them to the dashboard, which displays a message