Example #1
0
 def test_login_fails_if_token_for_different_site_url(self):
     self.site.users.create_item('*****@*****.**')
     token = generate_login_token(
         self.site, 'https://foo.com', '*****@*****.**')
     response = self.get('/wwwhisper/auth/api/login/?token=' + token)
     self.assertEqual(400, response.status_code)
     self.assertEqual('Token invalid or expired.', response.content)
Example #2
0
 def test_login_fails_if_unknown_user(self):
     token = generate_login_token(self.site, TEST_SITE, '*****@*****.**')
     response = self.get('/wwwhisper/auth/api/login/?token=' + token,
                         HTTP_ACCEPT='text/plain, text/html')
     self.assertEqual(403, response.status_code)
     self.assertRegexpMatches(response['Content-Type'], 'text/html')
     self.assertRegexpMatches(response.content, '<body')
Example #3
0
 def test_login_succeeds_if_known_user(self):
     self.site.users.create_item('*****@*****.**')
     token = generate_login_token(self.site, TEST_SITE, '*****@*****.**')
     params = urllib.urlencode(dict(token=token, next='/foo'))
     response = self.get('/wwwhisper/auth/api/login/?' + params)
     self.assertEqual(302, response.status_code)
     self.assertEqual(TEST_SITE + '/foo', response['Location'])
Example #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}] 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()
Example #5
0
 def test_login_succeeds_if_known_user(self):
     self.site.users.create_item('*****@*****.**')
     token = generate_login_token(self.site, TEST_SITE, '*****@*****.**')
     params = urllib.urlencode(dict(token=token, next='/foo'))
     response = self.get('/wwwhisper/auth/api/login/?' + params)
     self.assertEqual(302, response.status_code)
     self.assertEqual(TEST_SITE + '/foo', response['Location'])
Example #6
0
 def test_login_fails_if_unknown_user(self):
     token = generate_login_token(self.site, TEST_SITE, '*****@*****.**')
     response = self.get('/wwwhisper/auth/api/login/?token=' + token,
                         HTTP_ACCEPT='text/plain, text/html')
     self.assertEqual(403, response.status_code)
     self.assertRegexpMatches(response['Content-Type'], 'text/html')
     self.assertRegexpMatches(response.content, '<body')
Example #7
0
 def test_login_fails_if_token_for_different_site_url(self):
     self.site.users.create_item('*****@*****.**')
     token = generate_login_token(self.site, 'https://foo.com',
                                  '*****@*****.**')
     response = self.get('/wwwhisper/auth/api/login/?token=' + token)
     self.assertEqual(400, response.status_code)
     self.assertEqual('Token invalid or expired.', response.content)
Example #8
0
 def test_login_succeeds_if_unknown_user_but_site_has_open_locations(self):
     location = self.site.locations.create_item('/foo/')
     location.grant_open_access(require_login=True)
     token = generate_login_token(self.site, TEST_SITE, '*****@*****.**')
     params = urllib.urlencode(dict(token=token, next='/foo'))
     response = self.get('/auth/api/login/?' + params)
     self.assertEqual(302, response.status_code)
     self.assertEqual(TEST_SITE + '/foo', response['Location'])
Example #9
0
 def test_successful_login_invalidates_token(self):
     self.site.users.create_item('*****@*****.**')
     token = generate_login_token(self.site, TEST_SITE, '*****@*****.**')
     response = self.get('/wwwhisper/auth/api/login/?token=' + token)
     self.assertEqual(302, response.status_code)
     response = self.get('/wwwhisper/auth/api/login/?token=' + token)
     self.assertEqual(400, response.status_code)
     self.assertEqual('Token invalid or expired.', response.content)
Example #10
0
 def test_login_succeeds_if_unknown_user_but_site_has_open_locations(self):
     location = self.site.locations.create_item('/foo/')
     location.grant_open_access(require_login=True)
     token = generate_login_token(self.site, TEST_SITE, '*****@*****.**')
     params = urllib.urlencode(dict(token=token, next='/foo'))
     response = self.get('/auth/api/login/?' + params)
     self.assertEqual(302, response.status_code)
     self.assertEqual(TEST_SITE + '/foo', response['Location'])
Example #11
0
 def test_successful_login_invalidates_token(self):
     self.site.users.create_item('*****@*****.**')
     token = generate_login_token(self.site, TEST_SITE, '*****@*****.**')
     response = self.get('/wwwhisper/auth/api/login/?token=' + token)
     self.assertEqual(302, response.status_code)
     response = self.get('/wwwhisper/auth/api/login/?token=' + token)
     self.assertEqual(400, response.status_code)
     self.assertEqual('Token invalid or expired.', response.content)
Example #12
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()
Example #13
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()
Example #14
0
 def test_token_for_different_site(self):
     user = self.site.users.create_item(TEST_USER_EMAIL)
     token = generate_login_token(
         self.site, 'http://example.com', TEST_USER_EMAIL)
     self.assertRaisesRegexp(AuthenticationError,
                             'Token invalid or expired',
                             self.backend.authenticate,
                             self.site,
                             TEST_SITE_URL,
                             token)
Example #15
0
 def test_tricky_redirection_replaced(self):
     # 'next' argument is not signed, so can be replaced by the
     # user. This is OK as long as all tricky paths are replaced.
     self.site.users.create_item('*****@*****.**')
     token = generate_login_token(self.site, TEST_SITE, '*****@*****.**')
     params = urllib.urlencode(dict(token=token, next='www.example.com'))
     response = self.get('/wwwhisper/auth/api/login/?' + params)
     self.assertEqual(302, response.status_code)
     # Ignore 'next' argument from the login URL
     self.assertEqual(TEST_SITE + '/', response['Location'])
Example #16
0
 def test_tricky_redirection_replaced(self):
     # 'next' argument is not signed, so can be replaced by the
     # user. This is OK as long as all tricky paths are replaced.
     self.site.users.create_item('*****@*****.**')
     token = generate_login_token(self.site, TEST_SITE, '*****@*****.**')
     params = urllib.urlencode(dict(token=token, next='www.example.com'))
     response = self.get('/wwwhisper/auth/api/login/?' + params)
     self.assertEqual(302, response.status_code)
     # Ignore 'next' argument from the login URL
     self.assertEqual(TEST_SITE + '/', response['Location'])
Example #17
0
    def test_user_cached_in_session(self):
        user = self.site.users.create_item('*****@*****.**')

        token = generate_login_token(self.site, TEST_SITE, '*****@*****.**')
        params = urllib.urlencode(dict(token=token, next='/foo'))
        response = self.get('/wwwhisper/auth/api/login/?' + params)
        self.assertEqual(302, response.status_code)

        s = self.client.session
        user_id = s['user_id']
        self.assertIsNotNone(user_id)
        self.assertEqual(user_id, user.id)
Example #18
0
    def test_user_cached_in_session(self):
        user = self.site.users.create_item('*****@*****.**')

        token = generate_login_token(self.site, TEST_SITE, '*****@*****.**')
        params = urllib.urlencode(dict(token=token, next='/foo'))
        response = self.get('/wwwhisper/auth/api/login/?' + params)
        self.assertEqual(302, response.status_code)

        s = self.client.session
        user_id = s['user_id']
        self.assertIsNotNone(user_id)
        self.assertEqual(user_id, user.id)
Example #19
0
 def login(self, email, site=None):
     if site is None:
         site = self.site
     token = generate_login_token(site, TEST_SITE, email)
     self.assertTrue(self.client.login(site=site, site_url=TEST_SITE, token=token))
     # Login needs to set user_id in session.
     user = site.users.find_item_by_email(email)
     self.assertIsNotNone(user)
     # Session must be stored in a temporary variable, otherwise
     # updating does not work.
     s = self.client.session
     s['user_id'] = user.id
     s.save()
Example #20
0
 def login(self, email, site=None):
     if site is None:
         site = self.site
     token = generate_login_token(site, TEST_SITE, email)
     self.assertTrue(self.client.login(
         site=site, site_url=TEST_SITE, token=token))
     # Login needs to set user_id in session.
     user = site.users.find_item_by_email(email)
     self.assertIsNotNone(user)
     # Session must be stored in a temporary variable, otherwise
     # updating does not work.
     s = self.client.session
     s['user_id'] = user.id
     s.save()
Example #21
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()
Example #22
0
 def user_token(self):
     return generate_login_token(self.site, TEST_SITE_URL, TEST_USER_EMAIL)
Example #23
0
 def test_load_valid_token(self):
     token = generate_login_token(self.site, TEST_SITE, '*****@*****.**')
     email = load_login_token(self.site, TEST_SITE, token)
     self.assertEqual('*****@*****.**', email)
Example #24
0
 def test_token_for_different_site(self):
     user = self.site.users.create_item(TEST_USER_EMAIL)
     token = generate_login_token(self.site, "http://example.com", TEST_USER_EMAIL)
     self.assertRaisesRegexp(
         AuthenticationError, "Token invalid or expired", self.backend.authenticate, self.site, TEST_SITE_URL, token
     )
Example #25
0
 def user_token(self):
     return generate_login_token(self.site, TEST_SITE_URL, TEST_USER_EMAIL)
Example #26
0
 def test_load_invalid_token(self):
     token = generate_login_token(self.site, TEST_SITE, '*****@*****.**')
     self.assertIsNone(load_login_token(self.site, TEST_SITE, token + 'x'))
Example #27
0
 def test_load_valid_token_for_different_site(self):
     token = generate_login_token(self.site, TEST_SITE, '*****@*****.**')
     self.assertIsNone(load_login_token(self.site, 'https://foo.org', token))