blob: 1273e04512385108cc5786587ef50e5eb7d5827e [file] [log] [blame]
#!/usr/bin/env python
#
# Copyright 2007 Google Inc.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
#
"""Tests for devappserver2.login."""
import Cookie
import unittest
import urllib
import wsgiref.util
from google.appengine.tools.devappserver2 import login
# Values used by many tests
COOKIE_NAME = 'my_fancy_cookie'
EMAIL = 'johnny@example.com'
USER_ID = '115914779145204185301'
class CookieTest(unittest.TestCase):
"""Tests for the cookie handling functions."""
def test_get_user_info_admin(self):
"""Tests the get_user_info function when the admin field is True."""
cookie_value = '%s:True:%s' % (EMAIL, USER_ID)
http_cookie = 'one=two; %s=%s; three=four' % (COOKIE_NAME, cookie_value)
email, admin, user_id = login.get_user_info(http_cookie,
cookie_name=COOKIE_NAME)
self.assertEqual(EMAIL, email)
self.assertTrue(admin)
self.assertEqual(USER_ID, user_id)
def test_get_user_info_not_admin(self):
"""Tests the get_user_info function when the admin field is False."""
cookie_value = '%s:False:%s' % (EMAIL, USER_ID)
http_cookie = 'one=two; %s=%s; three=four' % (COOKIE_NAME, cookie_value)
email, admin, user_id = login.get_user_info(http_cookie,
cookie_name=COOKIE_NAME)
self.assertEqual(EMAIL, email)
self.assertFalse(admin)
self.assertEqual(USER_ID, user_id)
def test_get_user_info_invalid_email(self):
"""Tests the get_user_info function when the admin field is False."""
cookie_value = 'foo:True:%s' % USER_ID
http_cookie = 'one=two; %s=%s; three=four' % (COOKIE_NAME, cookie_value)
email, admin, user_id = login.get_user_info(http_cookie,
cookie_name=COOKIE_NAME)
self.assertEqual('', email)
self.assertFalse(admin)
self.assertEqual('', user_id)
def test_get_user_info_does_not_exist(self):
"""Tests the get_user_info function when the cookie is not present."""
http_cookie = 'one=two; three=four'
email, admin, user_id = login.get_user_info(http_cookie,
cookie_name=COOKIE_NAME)
self.assertEqual('', email)
self.assertFalse(admin)
self.assertEqual('', user_id)
def test_get_user_info_bad_cookie(self):
"""Tests the get_user_info function when the cookie is malformed."""
cookie_name = 'SinaRot/g/get' # seen in the wild
cookie_value = 'blah'
http_cookie = '%s=%s' % (cookie_name, cookie_value)
email, admin, user_id = login.get_user_info(http_cookie,
cookie_name=cookie_name)
self.assertEqual('', email)
self.assertFalse(admin)
self.assertEqual('', user_id)
def test_get_user_info_from_dict_admin(self):
"""Tests the get_user_info function when the admin field is True."""
cookie_value = '%s:True:%s' % (EMAIL, USER_ID)
cookie_dict = {'one': 'two', COOKIE_NAME: cookie_value, 'three': 'four'}
email, admin, user_id = login._get_user_info_from_dict(
cookie_dict, cookie_name=COOKIE_NAME)
self.assertEqual(EMAIL, email)
self.assertTrue(admin)
self.assertEqual(USER_ID, user_id)
def test_get_user_info_from_dict_not_admin(self):
"""Tests the get_user_info function when the admin field is False."""
cookie_value = '%s:False:%s' % (EMAIL, USER_ID)
cookie_dict = {'one': 'two', COOKIE_NAME: cookie_value, 'three': 'four'}
email, admin, user_id = login._get_user_info_from_dict(
cookie_dict, cookie_name=COOKIE_NAME)
self.assertEqual(EMAIL, email)
self.assertFalse(admin)
self.assertEqual(USER_ID, user_id)
def test_get_user_info_from_dict_does_not_exist(self):
"""Tests the get_user_info function when the cookie is not present."""
cookie_dict = {'one': 'two', 'three': 'four'}
email, admin, user_id = login._get_user_info_from_dict(
cookie_dict, cookie_name=COOKIE_NAME)
self.assertEqual('', email)
self.assertFalse(admin)
self.assertEqual('', user_id)
def test_set_user_info_cookie(self):
"""Tests the set_user_info_cookie function."""
cookie_value = '%s:True:%s' % (EMAIL, USER_ID)
expected_result = '%s="%s"; Path=/' % (COOKIE_NAME, cookie_value)
result = login._set_user_info_cookie(EMAIL, True, cookie_name=COOKIE_NAME)
self.assertEqual(expected_result, result)
def test_clear_user_info_cookie(self):
"""Tests the clear_user_info_cookie function."""
expected_result = '%s=; Max-Age=0; Path=/' % COOKIE_NAME
result = login._clear_user_info_cookie(cookie_name=COOKIE_NAME)
self.assertEqual(expected_result, result)
class LoginRedirectTest(unittest.TestCase):
"""Tests the login_redirect function."""
def test_basic(self):
"""Tests that redirects are written back to the user."""
application_url = 'http://foo.com:1234'
continue_url = ('http://foo.com:1234/my/album/of/pictures?'
'with=some&query=parameters')
expected_location = (
'http://foo.com:1234/_ah/login?continue='
'http%3A//foo.com%3A1234'
'/my/album/of/pictures%3Fwith%3Dsome%26query%3Dparameters')
def start_response(status, headers, exc_info=None):
self.assertTrue(status.startswith('302'))
headers = dict(headers)
self.assertEqual({'Location': expected_location}, headers)
self.assertEqual(None, exc_info)
body = login.login_redirect(application_url, continue_url, start_response)
self.assertEqual('', ''.join(body))
class LoginPageTest(unittest.TestCase):
"""Tests the various ways of invoking the login page."""
def test_no_params(self):
"""Tests just accessing the login URL with no params."""
host = 'foo.com:1234'
path_info = '/_ah/login'
cookie_dict = {}
action = ''
set_email = ''
set_admin = False
continue_url = ''
status, location, set_cookie, content_type = self._run_test(
host, path_info, cookie_dict, action, set_email, set_admin,
continue_url)
self.assertEqual(200, status)
self.assertFalse(location)
self.assertFalse(set_cookie)
self.assertEqual('text/html', content_type)
def test_login(self):
"""Tests when setting the user info with and without continue URL."""
host = 'foo.com:1234'
path_info = '/_ah/login'
cookie_dict = {}
action = 'Login'
set_email = EMAIL
set_admin = False
continue_url = ''
expected_set = login._set_user_info_cookie(set_email, set_admin).strip()
# No continue URL.
status, location, set_cookie, _ = self._run_test(
host, path_info, cookie_dict, action, set_email, set_admin,
continue_url)
self.assertEqual(302, status)
self.assertEqual('http://%s%s' % (host, path_info), location)
self.assertEqual(expected_set, set_cookie)
self.assertIsInstance(location, str)
self.assertIsInstance(set_cookie, str)
# Continue URL.
continue_url = 'http://foo.com/blah'
status, location, set_cookie, _ = self._run_test(
host, path_info, cookie_dict, action, set_email, set_admin,
continue_url)
self.assertEqual(302, status)
self.assertEqual(continue_url, location)
self.assertEqual(expected_set, set_cookie)
self.assertIsInstance(location, str)
self.assertIsInstance(set_cookie, str)
def test_logout(self):
"""Tests when logging out with and without continue URL."""
host = 'foo.com:1234'
path_info = '/_ah/login'
cookie_dict = {'dev_appserver_login': '%s:False:%s' % (EMAIL, USER_ID)}
action = 'Logout'
set_email = ''
set_admin = False
continue_url = ''
expected_set = login._clear_user_info_cookie().strip()
# No continue URL.
status, location, set_cookie, _ = self._run_test(
host, path_info, cookie_dict, action, set_email, set_admin,
continue_url)
self.assertEqual(302, status)
self.assertEqual('http://%s%s' % (host, path_info), location)
self.assertEqual(expected_set, set_cookie)
self.assertIsInstance(location, str)
self.assertIsInstance(set_cookie, str)
# Continue URL.
continue_url = 'http://foo.com/blah'
status, location, set_cookie, _ = self._run_test(
host, path_info, cookie_dict, action, set_email, set_admin,
continue_url)
self.assertEqual(302, status)
self.assertEqual(continue_url, location)
self.assertEqual(expected_set, set_cookie)
self.assertIsInstance(location, str)
self.assertIsInstance(set_cookie, str)
def test_passive(self):
"""Tests when the user is already logged in."""
host = 'foo.com:1234'
path_info = '/_ah/login'
cookie_dict = {'dev_appserver_login': '%s:False:%s' % (EMAIL, USER_ID)}
action = ''
set_email = ''
set_admin = False
continue_url = '/my/fancy/url'
# Continue URL.
continue_url = 'http://foo.com/blah'
status, location, set_cookie, content_type = self._run_test(
host, path_info, cookie_dict, action, set_email, set_admin,
continue_url)
self.assertEqual(200, status)
self.assertFalse(location)
self.assertFalse(set_cookie)
self.assertEqual('text/html; charset=utf-8', content_type)
self.assertIsInstance(content_type, str)
def _run_test(self, host, path_info='/', cookie_dict=None, action=None,
set_email=None, set_admin=None, continue_url=None,
method='GET'):
"""Runs the login HTTP handler, returning information about the response.
Args:
host: The value of the HTTP Host header.
path_info: The absolute path of the request.
cookie_dict: A cookie dictionary with the existing cookies.
action: Value of the 'action' query argument.
set_email: Value of the 'email' query argument.
set_admin: Value of the 'admin' query argument.
continue_url: Value of the 'continue' query argument.
method: The HTTP method (e.g., 'GET').
Returns:
Tuple (status, location, set_cookie, content_type) where each
value is the value of the corresponding header from the
response; if no header exists, the value will be None. In the
case of status, it will just return the integer status code
and not the rest of the status message.
"""
environ = {}
wsgiref.util.setup_testing_defaults(environ)
# The SERVER_NAME should never be used by the login module -- always defer
# to the HTTP Host (so the user is not redirected to a different domain).
environ['SERVER_NAME'] = 'do_not_use'
environ['SERVER_PORT'] = '666'
environ['SERVER_PROTOCOL'] = 'HTTP/1.1'
environ['HTTP_HOST'] = host
environ['PATH_INFO'] = path_info
environ['REQUEST_METHOD'] = method
if cookie_dict:
cookie = Cookie.SimpleCookie(cookie_dict)
cookie_value = ';'.join(m.OutputString() for m in cookie.values())
environ['HTTP_COOKIE'] = cookie_value
query_dict = {}
if action:
query_dict['action'] = action
if set_email:
query_dict['email'] = set_email
if set_admin:
query_dict['admin'] = set_admin
if continue_url:
query_dict['continue'] = continue_url
if query_dict:
environ['QUERY_STRING'] = urllib.urlencode(query_dict)
response_dict = {}
def start_response(status, headers):
response_dict['status'] = int(status.split(' ', 1)[0])
response_dict['headers'] = dict((k.lower(), v)
for (k, v) in headers)
login.application(environ, start_response)
return (response_dict['status'],
response_dict['headers'].get('location'),
response_dict['headers'].get('set-cookie'),
response_dict['headers'].get('content-type'))
if __name__ == '__main__':
unittest.main()