Beispiel #1
0
    def post(self, request, email, path):
        """Emails login url with secret token to verify email ownership.

        Token is signed (but not encrypted) and valid only for the
        current site.

        The login url contains a path to which the user should be
        redirected after successful verification.
        """
        if email == None:
            return http.HttpResponseBadRequest('Email not set.')
        if not models.is_email_valid(email):
            return http.HttpResponseBadRequest('Email has invalid format.')
        if path is None or not url_utils.validate_redirection_target(path):
            path = '/'

        token = login_token.generate_login_token(request.site,
                                                 site_url=request.site_url,
                                                 email=email)

        params = urllib.urlencode(dict(next=path, token=token))
        url = '{0}{1}?{2}'.format(request.site_url, reverse('login'), params)
        subject = '[{0}] email verification'.format(request.site_url)
        from_email = settings.TOKEN_EMAIL_FROM
        body = (
            'Follow the link to verify your email address\n' +
            '{0}\n'.format(url) + '\n' +
            'Ignore this email if you have not requested such verification.')
        send_mail(subject, body, from_email, [email], fail_silently=False)
        return http.HttpResponseNoContent()
Beispiel #2
0
    def post(self, request, email, path):
        """If the email owner can access the site, sends the login token.

        Token is not sent if the email owner is not allowed to access
        the site in order to avoid abusing this end point to send a
        flood of emails to unknown addresses.

        Token is signed (but not encrypted) and valid only for the
        current site.

        The login url contains a path to which the user should be
        redirected after successful verification.
        """
        if email == None:
            return http.HttpResponseBadRequest('Email not set.')
        if not models.is_email_valid(email):
            return http.HttpResponseBadRequest('Email has invalid format.')
        if path is None or not url_utils.validate_redirection_target(path):
            path = '/'

        if request.site.users.find_item_by_email(email) is None:
            # The email owner can not access the site. The token is
            # not sent, but the response is identical to the response
            # returned when the token is sent. This way it is not
            # possible to use the login form to query which emails are
            # allowed access. Such queries can still be possible by
            # response timing.
            return http.HttpResponseNoContent()

        token = login_token.generate_login_token(request.site,
                                                 site_url=request.site_url,
                                                 email=email)

        params = urllib.urlencode(dict(next=path, token=token))
        url = '{0}{1}?{2}'.format(request.site_url, reverse('login'), params)
        subject = '{0} access token'.format(request.site_url)
        body = (
            'Hello,\n\n'
            'You have requested access to {0}.\n'.format(request.site_url) +
            'Open this link to verify your email address:\n\n'
            '{0}\n\n'.format(url) +
            'If you have not requested such access, please ignore this email.\n'
            'The link is valid for the next 30 minutes and can be used once.\n'
        )
        from_email = settings.TOKEN_EMAIL_FROM
        success = False
        try:
            success = (send_mail(
                subject, body, from_email, [email], fail_silently=False) > 0)
        except Exception as ex:
            logger.warning(ex)
        if not success:
            # This probaly can be also due to invalid email address,
            # in these cases 400 would be better.
            msg = 'Email delivery problem. ' \
                'Check the entered address or try again in a few minutes.'
            return http.HttpResponseInternalError(msg)
        return http.HttpResponseNoContent()
Beispiel #3
0
    def post(self, request, email, path):
        """If the email owner can access the site, sends the login token.

        Token is not sent if the email owner is not allowed to access
        the site in order to avoid abusing this end point to send a
        flood of emails to unknown addresses.

        Token is signed (but not encrypted) and valid only for the
        current site.

        The login url contains a path to which the user should be
        redirected after successful verification.
        """
        if email == None:
            return http.HttpResponseBadRequest('Email not set.')
        if not models.is_email_valid(email):
            return http.HttpResponseBadRequest('Email has invalid format.')
        if path is None or not url_utils.validate_redirection_target(path):
            path = '/'

        if request.site.users.find_item_by_email(email) is None:
            # The email owner can not access the site. The token is
            # not sent, but the response is identical to the response
            # returned when the token is sent. This way it is not
            # possible to use the login form to query which emails are
            # allowed access. Such queries can still be possible by
            # response timing.
            return http.HttpResponseNoContent();

        token = login_token.generate_login_token(
            request.site, site_url=request.site_url, email=email)

        params = urllib.urlencode(dict(next=path, token=token))
        url = '{0}{1}?{2}'.format(request.site_url, reverse('login'), params)
        subject = '{0} access token'.format(request.site_url)
        body = (
            'Hello,\n\n'
            'You have requested access to {0}.\n'.format(request.site_url) +
            'Open this link to verify your email address:\n\n'
            '{0}\n\n'.format(url) +
            'If you have not requested such access, please ignore this email.\n'
            'The link is valid for the next 30 minutes and can be used once.\n'
        )
        from_email = settings.TOKEN_EMAIL_FROM
        success = False
        try:
            success = (send_mail(subject, body, from_email, [email],
                                 fail_silently=False) > 0)
        except Exception as ex:
            logger.warning(ex)
        if not success:
            # This probaly can be also due to invalid email address,
            # in these cases 400 would be better.
            msg = 'Email delivery problem. ' \
                'Check the entered address or try again in a few minutes.'
            return http.HttpResponseInternalError(msg)
        return http.HttpResponseNoContent()
Beispiel #4
0
    def post(self, request, email, path):
        """Emails login url with secret token to verify email ownership.

        Token is signed (but not encrypted) and valid only for the
        current site.

        The login url contains a path to which the user should be
        redirected after successful verification.
        """
        if email == None:
            return http.HttpResponseBadRequest('Email not set.')
        if not models.is_email_valid(email):
            return http.HttpResponseBadRequest('Email has invalid format.')
        if path is None or not url_utils.validate_redirection_target(path):
            path = '/'

        token = login_token.generate_login_token(
            request.site, site_url=request.site_url, email=email)

        params = urllib.urlencode(dict(next=path, token=token))
        url = '{0}{1}?{2}'.format(request.site_url, reverse('login'), params)
        subject = '{0} access token'.format(request.site_url)
        body = (
            'Hello,\n\n'
            'You have requested access to {0}.\n'.format(request.site_url) +
            'Open this link to verify your email address:\n\n'
            '{0}\n\n'.format(url) +
            'If you have not requested such access, please ignore this email.\n'
            'The link is valid for the next 30 minutes and can be used once.\n'
        )
        from_email = settings.TOKEN_EMAIL_FROM
        success = False
        try:
            success = (send_mail(subject, body, from_email, [email],
                                 fail_silently=False) > 0)
        except Exception as ex:
            logger.warning(ex)
        if not success:
            # This probaly can be also due to invalid email address,
            # in these cases 400 would be better.
            msg = 'Email delivery problem. ' \
                'Check the entered address or try again in a few minutes.'
            return http.HttpResponseInternalError(msg)
        return http.HttpResponseNoContent()
Beispiel #5
0
    def get(self, request):
        """Logs a user in (establishes a session cookie).

        Verifies a token and check that a user with an email encoded
        in the token is known.

        On success redirects to path passed in the 'next' url
        argument.
        """
        # TODO(jw): should this first check if the user is already
        # logged in and redirect to '/' if this is the case?
        token = request.GET.get('token')
        if token == None:
            return http.HttpResponseBadRequest('Token missing.')
        try:
            user = auth.authenticate(site=request.site,
                                     site_url=request.site_url,
                                     token=token)
        except AuthenticationError as ex:
            logger.debug('Token verification failed.')
            return http.HttpResponseBadRequest(str(ex))
        if user is not None:
            auth.login(request, user)
            user.login_successful()

            # Store all user data needed by Auth view in session, this
            # way, user table does not need to be queried during the
            # performance critical request (sessions are cached).
            request.session['user_id'] = user.id
            logger.debug('%s successfully logged.' % (user.email))
            redirect_to = request.GET.get('next')
            if (redirect_to is None
                    or not url_utils.validate_redirection_target(redirect_to)):
                redirect_to = '/'

            return http.HttpResponseRedirect(request.site_url + redirect_to)

        # Return not authorized because request was well formed (400
        # doesn't seem appropriate).
        return http.HttpResponseNotAuthorized(
            _html_or_none(request, 'nothing_accessible.html'))
Beispiel #6
0
    def get(self, request):
        """Logs a user in (establishes a session cookie).

        Verifies a token and check that a user with an email encoded
        in the token is known.

        On success redirects to path passed in the 'next' url
        argument.
        """
        # TODO(jw): should this first check if the user is already
        # logged in and redirect to '/' if this is the case?
        token = request.GET.get('token')
        if token == None:
            return http.HttpResponseBadRequest('Token missing.')
        try:
            user = auth.authenticate(site=request.site,
                                     site_url=request.site_url,
                                     token=token)
        except AuthenticationError as ex:
            logger.debug('Token verification failed.')
            return http.HttpResponseBadRequest(str(ex))
        if user is not None:
            auth.login(request, user)
            user.login_successful()

            # Store all user data needed by Auth view in session, this
            # way, user table does not need to be queried during the
            # performance critical request (sessions are cached).
            request.session['user_id'] = user.id
            logger.debug('%s successfully logged.' % (user.email))
            redirect_to = request.GET.get('next')
            if (redirect_to is None or
                not url_utils.validate_redirection_target(redirect_to)):
                redirect_to = '/'

            return http.HttpResponseRedirect(request.site_url + redirect_to)

        # Return not authorized because request was well formed (400
        # doesn't seem appropriate).
        return http.HttpResponseNotAuthorized(
            _html_or_none(request, 'nothing_accessible.html'))
Beispiel #7
0
    def test_validate_redirection_target(self):
        self.assertTrue(validate_redirection_target('/'))
        self.assertTrue(validate_redirection_target('/foo'))
        self.assertTrue(validate_redirection_target('/foo/'))
        self.assertTrue(validate_redirection_target('/foo/?bar=baz'))
        self.assertTrue(validate_redirection_target('/foo?bar=baz/../'))

        self.assertFalse(validate_redirection_target(''))
        self.assertFalse(validate_redirection_target('/' + 'f' * 200))
        self.assertFalse(validate_redirection_target('http://example.org/'))
        self.assertFalse(validate_redirection_target('example.org/'))
        self.assertFalse(validate_redirection_target('/foo\n'))
        self.assertFalse(validate_redirection_target('/foo/../bar'))
        self.assertFalse(validate_redirection_target(''))