Example #1
0
def authenticate_users(email, password):
    """
    Yup, this is a 'util' method instead of a proper authentication backend.
    The reason for this is that as our membersystem allows duplicate email
    fields, a user can potentially authenticate herself for multiple accounts,
    and the Django auth backend system doesn't account for that (it returns
    exactly one user, or None).
    """
    email = email.strip()

    # Support this special case explicitly because it will hit a lot of Actors
    # and check for a matching User for each of them, which takes a long time
    if email == '':
        return []

    # Add matching local users that aren't members
    matches = [
        u
        for u in User.get_users().filter(
            memberid__isnull=True,
            email__iexact=email
        )
        if u.check_password(password)
    ]

    # Add matching members in Actor
    for actor in Actor.get_personal_members().filter(email__iexact=email):
        try:
            # Ok, look for any matching active user
            user = User.get_users(
                include_pending=True,
                include_expired=True
            ).get(
                memberid=actor.memberid,
                is_inactive=False  # ignore inactive users
            )

            # Reset state if this user was previously pending but is now a
            # proper member
            if user.is_pending:
                user.is_pending = False
                user.save()

            # Reset state if this user was previously marked as expired for
            # some reason
            if user.is_expired:
                user.is_expired = False
                user.save()

            # Now perform the password check for authentication
            if user.check_password(password):
                matches.append(user)
        except User.DoesNotExist:
            pass

    # Add matching pending members
    for enrollment in Enrollment.filter_on_email(email):
        try:
            # Ok, look for any matching active AND pending user
            user = User.get_users(
                include_pending=True,
                include_expired=True
            ).get(
                memberid=enrollment.memberid,
                is_pending=True,
                is_inactive=False  # ignore inactive users
            )

            # Reset state if this user was previously marked as expired for
            # some reason
            if user.is_expired:
                user.is_expired = False
                user.save()

            # Now perform the password check for authentication
            # Check that the user isn't already matched as an Actor since this
            # theoretically could be a duplicate
            if user.check_password(password) and user not in matches:
                matches.append(user)
        except User.DoesNotExist:
            pass

    # And just return these matches
    return matches
Example #2
0
def send_restore_password_email(request):
    if 'email' not in request.POST:
        raise PermissionDenied

    email = request.POST['email'].strip()

    if not validator.email(email):
        return HttpResponse(json.dumps({'status': 'invalid_email'}))

    # The address might match one non-member, check it:
    local_matches = list(User.objects.filter(memberid__isnull=True, email=email))

    # The address might match several members, registered or not
    focus_unregistered_matches = False

    # Search through matching Actors
    for actor in Actor.get_personal_members().filter(email=email):
        try:
            # Ok, look for any matching active user
            user = User.get_users(
                include_pending=True,
                include_expired=True
            ).get(
                memberid=actor.memberid,
                is_inactive=False # ignore inactive users; these need to register first
            )

            # Reset state if this user was previously pending but is now a proper member
            if user.is_pending:
                user.is_pending = False
                user.save()

            # Reset state if this user was previously marked as expired for some reason
            if user.is_expired:
                user.is_expired = False
                user.save()

            local_matches.append(user)
        except User.DoesNotExist:
            # There is an actor but no corresponding user - inform the user that they need to register
            focus_unregistered_matches = True

    # Now search through matching active enrollments
    for enrollment in Enrollment.filter_on_email(email):
        try:
            # Ok, look for any matching active AND pending user
            user = User.get_users(
                include_pending=True,
                include_expired=True
            ).get(
                memberid=enrollment.memberid,
                is_pending=True,
                is_inactive=False # ignore inactive users; these need to register first
            )

            # Reset state if this user was previously marked as expired for some reason
            if user.is_expired:
                user.is_expired = False
                user.save()

            # Check that the user isn't already matched as an Actor since this theoretically could be a duplicate
            if user not in local_matches:
                local_matches.append(user)
        except User.DoesNotExist:
            pass

    if len(local_matches) == 0:
        # No email-address matches.
        if focus_unregistered_matches:
            # Oh, the email address exists in Focus, but the user(s) aren't in our user-base. Let them know.
            return HttpResponse(json.dumps({'status': 'unregistered_email'}))
        else:
            return HttpResponse(json.dumps({'status': 'unknown_email'}))
    else:
        for user in local_matches:
            key = crypto.get_random_string(length=settings.RESTORE_PASSWORD_KEY_LENGTH)
            while User.objects.filter(password_restore_key=key).exists():
                # Ensure that the key isn't already in use. With the current key length of 40, we'll have
                # ~238 bits of entropy which means that this will never ever happen, ever.
                # You will win the lottery before this happens. And I want to know if it does, so log it.
                logger.warning(
                    "Noen fikk en random-generert password-restore-key som allerede finnes!",
                    extra={
                        'request': request,
                        'should_you_play_the_lottery': True,
                        'key': key
                    }
                )
                key = crypto.get_random_string(length=settings.RESTORE_PASSWORD_KEY_LENGTH)

            user.password_restore_key = key
            user.password_restore_date = datetime.now()
            user.save()

        if len(local_matches) == 1:
            context = {
                'found_user': user,
                'validity_period': settings.RESTORE_PASSWORD_VALIDITY,
            }
            message = render_to_string('common/user/login/restore-password-email.txt', context, request=request)
        else:
            context = {
                'users': local_matches,
                'validity_period': settings.RESTORE_PASSWORD_VALIDITY,
            }
            message = render_to_string(
                'common/user/login/restore-password-email-multiple.txt',
                context,
                request=request,
            )
        send_mail("Nytt passord på Min side", message, settings.DEFAULT_FROM_EMAIL, [email])
    return HttpResponse(json.dumps({'status': 'success'}))