Exemple #1
0
    def create_retirement(cls, user):
        """
        Creates a UserRetirementStatus for the given user, in the correct initial state. Will
        fail if the user already has a UserRetirementStatus row or if states are not yet populated.
        """
        try:
            pending = RetirementState.objects.all().order_by('state_execution_order')[0]
        except IndexError:
            raise RetirementStateError('Default state does not exist! Populate retirement states to retire users.')

        if cls.objects.filter(user=user).exists():
            raise RetirementStateError('User {} already has a retirement status row!'.format(user))

        retired_username = get_retired_username_by_username(user.username)
        retired_email = get_retired_email_by_email(user.email)

        UserRetirementRequest.create_retirement_request(user)

        return cls.objects.create(
            user=user,
            original_username=user.username,
            original_email=user.email,
            original_name=user.profile.name,
            retired_username=retired_username,
            retired_email=retired_email,
            current_state=pending,
            last_state=pending,
            responses='Created in state {} by create_retirement'.format(pending)
        )
def test_get_retired_email():
    """
    Basic testing of retired emails.
    """
    user = UserFactory()
    hashed_email = get_retired_email_by_email(user.email)
    check_email_against_fmt(hashed_email)
Exemple #3
0
    def post(self, request):
        """
        POST /api/user/v1/accounts/deactivate_logout

        Marks the user as having no password set for deactivation purposes,
        and logs the user out.
        """
        username = request.data.get('user', None)
        if not username:
            return Response(status=status.HTTP_404_NOT_FOUND,
                            data={'message': u'The user was not specified.'})

        user_model = get_user_model()
        try:
            # make sure the specified user exists
            user = user_model.objects.get(username=username)

            with transaction.atomic():
                # 1. Unlink LMS social auth accounts
                UserSocialAuth.objects.filter(user_id=user.id).delete()
                # 2. Change LMS password & email
                user.email = get_retired_email_by_email(user.email)
                user.save()
                _set_unusable_password(user)
                # 3. Unlink social accounts & change password on each IDA, still to be implemented
        except user_model.DoesNotExist:
            return Response(status=status.HTTP_404_NOT_FOUND)
        except Exception as exc:  # pylint: disable=broad-except
            return Response(text_type(exc),
                            status=status.HTTP_500_INTERNAL_SERVER_ERROR)

        return Response(status=status.HTTP_204_NO_CONTENT)
Exemple #4
0
def test_get_retired_email():
    """
    Basic testing of retired emails.
    """
    user = UserFactory()
    hashed_email = get_retired_email_by_email(user.email)
    check_email_against_fmt(hashed_email)
Exemple #5
0
    def post(self, request):
        """
        POST /api/user/v1/accounts/retire/

        {
            'username': '******'
        }

        Retires the user with the given username.  This includes
        retiring this username, the associates email address, and
        any other PII associated with this user.
        """
        username = request.data['username']
        if is_username_retired(username):
            return Response(status=status.HTTP_404_NOT_FOUND)

        try:
            retirement_status = UserRetirementStatus.get_retirement_for_retirement_action(username)
            user = retirement_status.user
            retired_username = retirement_status.retired_username or get_retired_username_by_username(username)
            retired_email = retirement_status.retired_email or get_retired_email_by_email(user.email)
            original_email = retirement_status.original_email

            # Retire core user/profile information
            self.clear_pii_from_userprofile(user)
            self.delete_users_profile_images(user)
            self.delete_users_country_cache(user)

            # Retire data from Enterprise models
            self.retire_users_data_sharing_consent(username, retired_username)
            self.retire_sapsf_data_transmission(user)
            self.retire_user_from_pending_enterprise_customer_user(user, retired_email)
            self.retire_entitlement_support_detail(user)

            # Retire misc. models that may contain PII of this user
            SoftwareSecurePhotoVerification.retire_user(user.id)
            PendingEmailChange.delete_by_user_value(user, field='user')
            UserOrgTag.delete_by_user_value(user, field='user')

            # Retire any objects linked to the user via their original email
            CourseEnrollmentAllowed.delete_by_user_value(original_email, field='email')
            UnregisteredLearnerCohortAssignments.delete_by_user_value(original_email, field='email')

            # TODO: Password Reset links - https://openedx.atlassian.net/browse/PLAT-2104
            # TODO: Delete OAuth2 records - https://openedx.atlassian.net/browse/EDUCATOR-2703

            user.first_name = ''
            user.last_name = ''
            user.is_active = False
            user.username = retired_username
            user.save()
        except UserRetirementStatus.DoesNotExist:
            return Response(status=status.HTTP_404_NOT_FOUND)
        except RetirementStateError as exc:
            return Response(text_type(exc), status=status.HTTP_400_BAD_REQUEST)
        except Exception as exc:  # pylint: disable=broad-except
            return Response(text_type(exc), status=status.HTTP_500_INTERNAL_SERVER_ERROR)

        return Response(status=status.HTTP_204_NO_CONTENT)
Exemple #6
0
    def post(self, request):
        """
        POST /api/user/v1/accounts/retire/

        {
            'username': '******'
        }

        Retires the user with the given username.  This includes
        retiring this username, the associates email address, and
        any other PII associated with this user.
        """
        username = request.data['username']
        if is_username_retired(username):
            return Response(status=status.HTTP_404_NOT_FOUND)

        try:
            retirement_status = UserRetirementStatus.get_retirement_for_retirement_action(username)
            user = retirement_status.user
            retired_username = retirement_status.retired_username or get_retired_username_by_username(username)
            retired_email = retirement_status.retired_email or get_retired_email_by_email(user.email)
            original_email = retirement_status.original_email

            # Retire core user/profile information
            self.clear_pii_from_userprofile(user)
            self.delete_users_profile_images(user)
            self.delete_users_country_cache(user)

            # Retire data from Enterprise models
            self.retire_users_data_sharing_consent(username, retired_username)
            self.retire_sapsf_data_transmission(user)
            self.retire_user_from_pending_enterprise_customer_user(user, retired_email)
            self.retire_entitlement_support_detail(user)

            # Retire misc. models that may contain PII of this user
            SoftwareSecurePhotoVerification.retire_user(user.id)
            PendingEmailChange.delete_by_user_value(user, field='user')
            UserOrgTag.delete_by_user_value(user, field='user')

            # Retire any objects linked to the user via their original email
            CourseEnrollmentAllowed.delete_by_user_value(original_email, field='email')
            UnregisteredLearnerCohortAssignments.delete_by_user_value(original_email, field='email')

            # TODO: Password Reset links - https://openedx.atlassian.net/browse/PLAT-2104
            # TODO: Delete OAuth2 records - https://openedx.atlassian.net/browse/EDUCATOR-2703

            user.first_name = ''
            user.last_name = ''
            user.is_active = False
            user.username = retired_username
            user.save()
        except UserRetirementStatus.DoesNotExist:
            return Response(status=status.HTTP_404_NOT_FOUND)
        except RetirementStateError as exc:
            return Response(text_type(exc), status=status.HTTP_400_BAD_REQUEST)
        except Exception as exc:  # pylint: disable=broad-except
            return Response(text_type(exc), status=status.HTTP_500_INTERNAL_SERVER_ERROR)

        return Response(status=status.HTTP_204_NO_CONTENT)
def test_get_retired_email_status_exists(retirement_user, retirement_status):  # pylint: disable=redefined-outer-name
    """
    Checks that a retired email is gotten from a UserRetirementStatus
    object when one already exists for a user.
    """
    hashed_email = get_retired_email_by_email(retirement_user.email)
    check_email_against_fmt(hashed_email)
    assert retirement_status.retired_email == hashed_email
Exemple #8
0
def test_get_retired_email_status_exists(retirement_user, retirement_status):  # pylint: disable=redefined-outer-name
    """
    Checks that a retired email is gotten from a UserRetirementStatus
    object when one already exists for a user.
    """
    hashed_email = get_retired_email_by_email(retirement_user.email)
    check_email_against_fmt(hashed_email)
    assert retirement_status.retired_email == hashed_email
Exemple #9
0
 def test_retired_email(self):
     """
     Assert the expected error message from the email validation method for an email address
     that corresponds with an already-retired account.
     """
     user = UserFactory.create(email=self.new_email)
     user.email = get_retired_email_by_email(self.new_email)
     user.save()
     self.assertEqual(self.do_email_validation(self.new_email), 'An account with this e-mail already exists.')
Exemple #10
0
    def post(self, request):
        """
        POST /api/user/v1/accounts/retire/

        {
            'username': '******'
        }

        Retires the user with the given username.  This includes
        retiring this username, the associated email address, and
        any other PII associated with this user.
        """
        username = request.data['username']

        try:
            retirement_status = UserRetirementStatus.get_retirement_for_retirement_action(username)
            user = retirement_status.user
            retired_username = retirement_status.retired_username or get_retired_username_by_username(username)
            retired_email = retirement_status.retired_email or get_retired_email_by_email(user.email)
            original_email = retirement_status.original_email

            # Retire core user/profile information
            self.clear_pii_from_userprofile(user)
            self.delete_users_profile_images(user)
            self.delete_users_country_cache(user)

            # Retire data from Enterprise models
            self.retire_users_data_sharing_consent(username, retired_username)
            self.retire_sapsf_data_transmission(user)
            self.retire_degreed_data_transmission(user)
            self.retire_user_from_pending_enterprise_customer_user(user, retired_email)
            self.retire_entitlement_support_detail(user)

            # Retire misc. models that may contain PII of this user
            PendingEmailChange.delete_by_user_value(user, field='user')
            UserOrgTag.delete_by_user_value(user, field='user')

            # Retire any objects linked to the user via their original email
            CourseEnrollmentAllowed.delete_by_user_value(original_email, field='email')
            UnregisteredLearnerCohortAssignments.delete_by_user_value(original_email, field='email')

            # This signal allows code in higher points of LMS to retire the user as necessary
            USER_RETIRE_LMS_CRITICAL.send(sender=self.__class__, user=user)

            user.first_name = ''
            user.last_name = ''
            user.is_active = False
            user.username = retired_username
            user.save()
        except UserRetirementStatus.DoesNotExist:
            return Response(status=status.HTTP_404_NOT_FOUND)
        except RetirementStateError as exc:
            return Response(text_type(exc), status=status.HTTP_400_BAD_REQUEST)
        except Exception as exc:  # pylint: disable=broad-except
            return Response(text_type(exc), status=status.HTTP_500_INTERNAL_SERVER_ERROR)

        return Response(status=status.HTTP_204_NO_CONTENT)
 def test_retired_email(self):
     """
     Assert the expected error message from the email validation method for an email address
     that corresponds with an already-retired account.
     """
     user = UserFactory.create(email=self.new_email)
     user.email = get_retired_email_by_email(self.new_email)
     user.save()
     self.assertEqual(self.do_email_validation(self.new_email), 'An account with this e-mail already exists.')
Exemple #12
0
    def post(self, request):
        """
        POST /api/user/v1/accounts/deactivate_logout/

        Marks the user as having no password set for deactivation purposes,
        and logs the user out.
        """
        user_model = get_user_model()
        try:
            # Get the username from the request and check that it exists
            verify_user_password_response = self._verify_user_password(request)
            if verify_user_password_response.status_code != status.HTTP_204_NO_CONTENT:
                return verify_user_password_response
            with transaction.atomic():
                UserRetirementStatus.create_retirement(request.user)
                # Unlink LMS social auth accounts
                UserSocialAuth.objects.filter(user_id=request.user.id).delete()
                # Change LMS password & email
                user_email = request.user.email
                request.user.email = get_retired_email_by_email(request.user.email)
                request.user.save()
                _set_unusable_password(request.user)
                # TODO: Unlink social accounts & change password on each IDA.
                # Remove the activation keys sent by email to the user for account activation.
                Registration.objects.filter(user=request.user).delete()
                # Add user to retirement queue.
                # Delete OAuth tokens associated with the user.
                retire_dop_oauth2_models(request.user)
                retire_dot_oauth2_models(request.user)

                try:
                    # Send notification email to user
                    site = Site.objects.get_current()
                    notification_context = get_base_template_context(site)
                    notification_context.update({'full_name': request.user.profile.name})
                    notification = DeletionNotificationMessage().personalize(
                        recipient=Recipient(username='', email_address=user_email),
                        language=request.user.profile.language,
                        user_context=notification_context,
                    )
                    ace.send(notification)
                except Exception as exc:
                    log.exception('Error sending out deletion notification email')
                    raise

                # Log the user out.
                logout(request)
            return Response(status=status.HTTP_204_NO_CONTENT)
        except KeyError:
            return Response(u'Username not specified.', status=status.HTTP_404_NOT_FOUND)
        except user_model.DoesNotExist:
            return Response(
                u'The user "{}" does not exist.'.format(request.user.username), status=status.HTTP_404_NOT_FOUND
            )
        except Exception as exc:  # pylint: disable=broad-except
            return Response(text_type(exc), status=status.HTTP_500_INTERNAL_SERVER_ERROR)
def test_is_email_retired_is_retired(retirement_user):
    """
    Check functionality of is_email_retired when email is retired
    """
    original_email = retirement_user.email
    retired_email = get_retired_email_by_email(retirement_user.email)

    # Fake email retirement.
    retirement_user.email = retired_email
    retirement_user.save()

    assert is_email_retired(original_email)
Exemple #14
0
def _fake_logged_out_user(user, retire_username=False):
    """
    Simulate the initial logout retirement endpoint.
    """
    # By default, do not change the username to the retired hash version because
    # that is not what happens upon actual retirement requests immediately after
    # logout.
    if retire_username:
        user.username = get_retired_username_by_username(user.username)
    user.email = get_retired_email_by_email(user.email)
    user.set_unusable_password()
    user.save()
Exemple #15
0
def test_is_email_retired_is_retired(retirement_user):
    """
    Check functionality of is_email_retired when email is retired
    """
    original_email = retirement_user.email
    retired_email = get_retired_email_by_email(retirement_user.email)

    # Fake email retirement.
    retirement_user.email = retired_email
    retirement_user.save()

    assert is_email_retired(original_email)
def _fake_logged_out_user(user, retire_username=False):
    """
    Simulate the initial logout retirement endpoint.
    """
    # By default, do not change the username to the retired hash version because
    # that is not what happens upon actual retirement requests immediately after
    # logout.
    if retire_username:
        user.username = get_retired_username_by_username(user.username)
    user.email = get_retired_email_by_email(user.email)
    user.set_unusable_password()
    user.save()
Exemple #17
0
def deactivate_user(user):
    """
    Deactivate and retire the given user
    """
    user_model = get_user_model()
    try:
        with transaction.atomic():
            UserRetirementStatus.create_retirement(user)
            # Unlink LMS social auth accounts
            UserSocialAuth.objects.filter(user_id=user.id).delete()
            # Change LMS password & email
            user_email = user.email
            user.email = get_retired_email_by_email(user.email)
            user.save()
            _set_unusable_password(user)
            # TODO: Unlink social accounts & change password on each IDA.
            # Remove the activation keys sent by email to the user for account activation.
            Registration.objects.filter(user=user).delete()
            # Add user to retirement queue.
            # Delete OAuth tokens associated with the user.
            retire_dop_oauth2_models(user)
            retire_dot_oauth2_models(user)
            try:
                # Send notification email to user
                site = Site.objects.get_current()
                notification_context = get_base_template_context(site)
                notification_context.update({'full_name': user.profile.name})
                notification_context.update({
                    'reset_password_link':
                    urlparse.urljoin(
                        settings.PROGS_URLS.get("ROOT"),
                        settings.PROGS_URLS.get("PROG_RESET_PASSWORD",
                                                "reset_password"))
                })
                notification = DeletionNotificationMessage().personalize(
                    recipient=Recipient(username='', email_address=user_email),
                    language=user.profile.language,
                    user_context=notification_context,
                )
                ace.send(notification)
            except Exception as exc:
                log.exception('Error sending out deletion notification email')
                raise
        return Response(status=status.HTTP_204_NO_CONTENT)
    except KeyError:
        return Response(u'Username not specified.',
                        status=status.HTTP_404_NOT_FOUND)
    except user_model.DoesNotExist:
        return Response(u'The user "{}" does not exist.'.format(user.username),
                        status=status.HTTP_404_NOT_FOUND)
    except Exception as exc:  # pylint: disable=broad-except
        return Response(text_type(exc),
                        status=status.HTTP_500_INTERNAL_SERVER_ERROR)
Exemple #18
0
def test_is_email_retired_is_retired():
    """
    Check functionality of is_email_retired when email is retired
    """
    user = UserFactory()
    original_email = user.email
    retired_email = get_retired_email_by_email(user.email)

    # Fake email retirement.
    user.email = retired_email
    user.save()

    assert is_email_retired(original_email)
def test_is_email_retired_is_retired():
    """
    Check functionality of is_email_retired when email is retired
    """
    user = UserFactory()
    original_email = user.email
    retired_email = get_retired_email_by_email(user.email)

    # Fake email retirement.
    user.email = retired_email
    user.save()

    assert is_email_retired(original_email)
Exemple #20
0
    def post(self, request):
        """
        POST /api/user/v1/accounts/retire/

        {
            'username': '******'
        }

        Retires the user with the given username.  This includes
        retiring this username, the associates email address, and
        any other PII associated with this user.
        """
        username = request.data['username']
        if is_username_retired(username):
            return Response(status=status.HTTP_404_NOT_FOUND)

        try:
            retirement_status = UserRetirementStatus.get_retirement_for_retirement_action(
                username)
            user = retirement_status.user
            retired_username = retirement_status.retired_username or get_retired_username_by_username(
                username)
            retired_email = retirement_status.retired_email or get_retired_email_by_email(
                user.email)

            self.clear_pii_from_userprofile(user)
            self.delete_users_profile_images(user)
            self.delete_users_country_cache(user)
            self.retire_users_data_sharing_consent(username, retired_username)
            self.retire_sapsf_data_transmission(user)
            self.retire_user_from_pending_enterprise_customer_user(
                user, retired_email)
            self.retire_entitlement_support_detail(user)
            # TODO: Password Reset links - https://openedx.atlassian.net/browse/PLAT-2104
            # TODO: Delete OAuth2 records - https://openedx.atlassian.net/browse/EDUCATOR-2703
            user.first_name = ''
            user.last_name = ''
            user.is_active = False
            user.username = retired_username
            user.save()
        except UserRetirementStatus.DoesNotExist:
            return Response(status=status.HTTP_404_NOT_FOUND)
        except RetirementStateError as exc:
            return Response(text_type(exc), status=status.HTTP_400_BAD_REQUEST)
        except Exception as exc:  # pylint: disable=broad-except
            return Response(text_type(exc),
                            status=status.HTTP_500_INTERNAL_SERVER_ERROR)

        return Response(status=status.HTTP_204_NO_CONTENT)
Exemple #21
0
def _assert_retirementstatus_is_user(retirement, user):
    """
    Helper function to compare a newly created UserRetirementStatus object to expected values for
    the given user.
    """
    pending = RetirementState.objects.all().order_by('state_execution_order')[0]
    retired_username = get_retired_username_by_username(user.username)
    retired_email = get_retired_email_by_email(user.email)

    assert retirement.user == user
    assert retirement.original_username == user.username
    assert retirement.original_email == user.email
    assert retirement.original_name == user.profile.name
    assert retirement.retired_username == retired_username
    assert retirement.retired_email == retired_email
    assert retirement.current_state == pending
    assert retirement.last_state == pending
    assert pending.state_name in retirement.responses
Exemple #22
0
def _assert_retirementstatus_is_user(retirement, user):
    """
    Helper function to compare a newly created UserRetirementStatus object to expected values for
    the given user.
    """
    pending = RetirementState.objects.all().order_by(
        'state_execution_order')[0]
    retired_username = get_retired_username_by_username(user.username)
    retired_email = get_retired_email_by_email(user.email)

    assert retirement.user == user
    assert retirement.original_username == user.username
    assert retirement.original_email == user.email
    assert retirement.original_name == user.profile.name
    assert retirement.retired_username == retired_username
    assert retirement.retired_email == retired_email
    assert retirement.current_state == pending
    assert retirement.last_state == pending
    assert pending.state_name in retirement.responses
Exemple #23
0
    def post(self, request):
        """
        POST /api/user/v1/accounts/deactivate_logout/

        Marks the user as having no password set for deactivation purposes,
        and logs the user out.
        """
        user_model = get_user_model()
        try:
            # Get the username from the request and check that it exists
            verify_user_password_response = self._verify_user_password(request)
            if verify_user_password_response.status_code != status.HTTP_204_NO_CONTENT:
                return verify_user_password_response
            with transaction.atomic():
                UserRetirementStatus.create_retirement(request.user)
                # Unlink LMS social auth accounts
                UserSocialAuth.objects.filter(user_id=request.user.id).delete()
                # Change LMS password & email
                request.user.email = get_retired_email_by_email(
                    request.user.email)
                request.user.save()
                _set_unusable_password(request.user)
                # TODO: Unlink social accounts & change password on each IDA.
                # Remove the activation keys sent by email to the user for account activation.
                Registration.objects.filter(user=request.user).delete()
                # Add user to retirement queue.
                # Delete OAuth tokens associated with the user.
                retire_dop_oauth2_models(request.user)
                retire_dot_oauth2_models(request.user)
                # Log the user out.
                logout(request)
            return Response(status=status.HTTP_204_NO_CONTENT)
        except KeyError:
            return Response(u'Username not specified.',
                            status=status.HTTP_404_NOT_FOUND)
        except user_model.DoesNotExist:
            return Response(u'The user "{}" does not exist.'.format(
                request.user.username),
                            status=status.HTTP_404_NOT_FOUND)
        except Exception as exc:  # pylint: disable=broad-except
            return Response(text_type(exc),
                            status=status.HTTP_500_INTERNAL_SERVER_ERROR)
    def _create_retirement(self, state, create_datetime=None):
        """
        Helper method to create a RetirementStatus with useful defaults
        """
        if create_datetime is None:
            create_datetime = datetime.datetime.now(pytz.UTC) - datetime.timedelta(days=8)

        user = UserFactory()
        return UserRetirementStatus.objects.create(
            user=user,
            original_username=user.username,
            original_email=user.email,
            original_name=user.profile.name,
            retired_username=get_retired_username_by_username(user.username),
            retired_email=get_retired_email_by_email(user.email),
            current_state=state,
            last_state=state,
            responses="",
            created=create_datetime,
            modified=create_datetime
        )
Exemple #25
0
    def post(self, request):
        """
        POST /api/user/v1/accounts/deactivate_logout/

        Marks the user as having no password set for deactivation purposes,
        and logs the user out.
        """
        user_model = get_user_model()
        try:
            # Get the username from the request and check that it exists
            verify_user_password_response = self._verify_user_password(request)
            if verify_user_password_response.status_code != status.HTTP_204_NO_CONTENT:
                return verify_user_password_response
            with transaction.atomic():
                UserRetirementStatus.create_retirement(request.user)
                # Unlink LMS social auth accounts
                UserSocialAuth.objects.filter(user_id=request.user.id).delete()
                # Change LMS password & email
                request.user.email = get_retired_email_by_email(request.user.email)
                request.user.save()
                _set_unusable_password(request.user)
                # TODO: Unlink social accounts & change password on each IDA.
                # Remove the activation keys sent by email to the user for account activation.
                Registration.objects.filter(user=request.user).delete()
                # Add user to retirement queue.
                # Delete OAuth tokens associated with the user.
                retire_dop_oauth2_models(request.user)
                retire_dot_oauth2_models(request.user)
                # Log the user out.
                logout(request)
            return Response(status=status.HTTP_204_NO_CONTENT)
        except KeyError:
            return Response(u'Username not specified.', status=status.HTTP_404_NOT_FOUND)
        except user_model.DoesNotExist:
            return Response(
                u'The user "{}" does not exist.'.format(request.user.username), status=status.HTTP_404_NOT_FOUND
            )
        except Exception as exc:  # pylint: disable=broad-except
            return Response(text_type(exc), status=status.HTTP_500_INTERNAL_SERVER_ERROR)
def fake_retirement(user):
    """
    Makes an attempt to put user for the given user into a "COMPLETED"
    retirement state by faking important parts of retirement.

    Use to test idempotency for retirement API calls. Since there are many
    configurable retirement steps this is only a "best guess" and may need
    additional changes added to more accurately reflect post-retirement state.
    """
    # Deactivate / logout and hash username & email
    UserSocialAuth.objects.filter(user_id=user.id).delete()
    user.first_name = ''
    user.last_name = ''
    user.is_active = False
    user.username = get_retired_username_by_username(user.username)
    user.email = get_retired_email_by_email(user.email)
    user.set_unusable_password()
    user.save()

    # Clear profile
    AccountRetirementView.clear_pii_from_userprofile(user)

    # Unenroll from all courses
    api.unenroll_user_from_all_courses(user.username)
Exemple #27
0
def delete_edxapp_user(*args, **kwargs):
    """
    Deletes a user from the platform.
    """
    msg = None

    user = kwargs.get("user")
    case_id = kwargs.get("case_id")
    site = kwargs.get("site")
    is_support_user = kwargs.get("is_support_user")

    user_response = "The user {username} <{email}> ".format(
        username=user.username, email=user.email)

    signup_sources = user.usersignupsource_set.all()
    sources = [signup_source.site for signup_source in signup_sources]

    if site and site.name.upper() in (source.upper() for source in sources):
        if len(sources) == 1:
            with transaction.atomic():
                support_label = "_support" if is_support_user else ""
                user.email = "{email}{case}.ednx{support}_retired".format(
                    email=user.email,
                    case=case_id,
                    support=support_label,
                )
                user.save()

                # Add user to retirement queue.
                UserRetirementStatus.create_retirement(user)

                # Unlink LMS social auth accounts
                UserSocialAuth.objects.filter(user_id=user.id).delete()

                # Change LMS password & email
                user.email = get_retired_email_by_email(user.email)
                user.save()
                _set_unusable_password(user)

                # Remove the activation keys sent by email to the user for account activation.
                Registration.objects.filter(user=user).delete()

                # Delete OAuth tokens associated with the user.
                retire_dot_oauth2_models(user)

                # Delete user signup source object
                signup_sources[0].delete()

                msg = "{user} has been removed".format(user=user_response)
        else:
            for signup_source in signup_sources:
                if signup_source.site.upper() == site.name.upper():
                    signup_source.delete()

                    msg = "{user} has more than one signup source. The signup source from the site {site} has been deleted".format(
                        user=user_response,
                        site=site,
                    )

        return msg, status.HTTP_200_OK

    raise NotFound(
        "{user} does not have a signup source on the site {site}".format(
            user=user_response, site=site))
Exemple #28
0
def _fake_logged_out_user(user):
    # Simulate the initial logout retirement endpoint.
    user.username = get_retired_username_by_username(user.username)
    user.email = get_retired_email_by_email(user.email)
    user.set_unusable_password()
    user.save()
Exemple #29
0
def password_change_request_handler(request):
    """Handle password change requests originating from the account page.

    Uses the Account API to email the user a link to the password reset page.

    Note:
        The next step in the password reset process (confirmation) is currently handled
        by student.views.password_reset_confirm_wrapper, a custom wrapper around Django's
        password reset confirmation view.

    Args:
        request (HttpRequest)

    Returns:
        HttpResponse: 200 if the email was sent successfully
        HttpResponse: 400 if there is no 'email' POST parameter
        HttpResponse: 403 if the client has been rate limited
        HttpResponse: 405 if using an unsupported HTTP method

    Example usage:

        POST /account/password

    """

    limiter = BadRequestRateLimiter()
    if limiter.is_rate_limit_exceeded(request):
        AUDIT_LOG.warning("Password reset rate limit exceeded")
        return HttpResponseForbidden()

    user = request.user
    # Prefer logged-in user's email
    email = user.email if user.is_authenticated else request.POST.get('email')

    if email:
        try:
            request_password_change(email, request.is_secure())
            if is_email_retired(email):
                email = get_retired_email_by_email(email)
            user = user if user.is_authenticated else User.objects.get(
                email=email)
            destroy_oauth_tokens(user)
        except UserNotFound:
            AUDIT_LOG.info("Invalid password reset attempt")
            # Increment the rate limit counter
            limiter.tick_bad_request_counter(request)

            # If enabled, send an email saying that a password reset was attempted, but that there is
            # no user associated with the email
            if configuration_helpers.get_value(
                    'ENABLE_PASSWORD_RESET_FAILURE_EMAIL',
                    settings.FEATURES['ENABLE_PASSWORD_RESET_FAILURE_EMAIL']):

                site = get_current_site()
                message_context = get_base_template_context(site)

                message_context.update({
                    'failed': True,
                    'request':
                    request,  # Used by google_analytics_tracking_pixel
                    'email_address': email,
                })

                msg = PasswordReset().personalize(
                    recipient=Recipient(username='', email_address=email),
                    language=settings.LANGUAGE_CODE,
                    user_context=message_context,
                )

                ace.send(msg)
        except UserAPIInternalError as err:
            log.exception(
                'Error occured during password change for user {email}: {error}'
                .format(email=email, error=err))
            return HttpResponse(_(
                "Some error occured during password change. Please try again"),
                                status=500)

        return HttpResponse(status=200)
    else:
        return HttpResponseBadRequest(_("No email address provided."))
Exemple #30
0
def test_get_retired_email(retirement_user):
    """
    Basic testing of retired emails.
    """
    hashed_email = get_retired_email_by_email(retirement_user.email)
    check_email_against_fmt(hashed_email)
def test_get_retired_email(retirement_user):
    """
    Basic testing of retired emails.
    """
    hashed_email = get_retired_email_by_email(retirement_user.email)
    check_email_against_fmt(hashed_email)