mirror of
https://salsa.debian.org/freeipa-team/freeipa.git
synced 2024-12-25 16:31:08 -06:00
1f6ca418ee
According to datetime.utcfromtimestamp() method documentation[1], this and similar methods fail for dates past 2038 and can be replaced by the following expression on the POSIX compliant systems: datetime(1970, 1, 1, tzinfo=timezone.utc) + timedelta(seconds=timestamp) Make sure to use a method that at least allows to import the timestamps properly to datetime objects on 32-bit platforms. [1] https://docs.python.org/3/library/datetime.html#datetime.datetime.utcfromtimestamp Fixes: https://pagure.io/freeipa/issue/8378 Signed-off-by: Alexander Bokovoy <abokovoy@redhat.com> Reviewed-By: Rob Crittenden <rcritten@redhat.com> Reviewed-By: Christian Heimes <cheimes@redhat.com>
508 lines
18 KiB
Python
508 lines
18 KiB
Python
# Authors:
|
|
# John Dennis <jdennis@redhat.com>
|
|
#
|
|
# Copyright (C) 2012 Red Hat
|
|
# see file 'COPYING' for use and warranty information
|
|
#
|
|
# This program is free software; you can redistribute it and/or modify
|
|
# it under the terms of the GNU General Public License as published by
|
|
# the Free Software Foundation, either version 3 of the License, or
|
|
# (at your option) any later version.
|
|
#
|
|
# This program is distributed in the hope that it will be useful,
|
|
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
# GNU General Public License for more details.
|
|
#
|
|
# You should have received a copy of the GNU General Public License
|
|
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
|
|
|
import datetime
|
|
import email.utils
|
|
from ipapython.cookie import Cookie
|
|
from ipapython.ipautil import datetime_from_utctimestamp
|
|
import pytest
|
|
|
|
pytestmark = pytest.mark.tier0
|
|
|
|
|
|
class TestParse:
|
|
|
|
def test_parse(self):
|
|
# Empty string
|
|
s = ''
|
|
cookies = Cookie.parse(s)
|
|
assert len(cookies) == 0
|
|
|
|
# Invalid single token
|
|
s = 'color'
|
|
with pytest.raises(ValueError):
|
|
cookies = Cookie.parse(s)
|
|
|
|
# Invalid single token that's keyword
|
|
s = 'HttpOnly'
|
|
with pytest.raises(ValueError):
|
|
cookies = Cookie.parse(s)
|
|
|
|
# Invalid key/value pair whose key is a keyword
|
|
s = 'domain=example.com'
|
|
with pytest.raises(ValueError):
|
|
cookies = Cookie.parse(s)
|
|
|
|
# 1 cookie with empty value
|
|
s = 'color='
|
|
cookies = Cookie.parse(s)
|
|
assert len(cookies) == 1
|
|
cookie = cookies[0]
|
|
assert cookie.key == 'color'
|
|
assert cookie.value == ''
|
|
assert cookie.domain is None
|
|
assert cookie.path is None
|
|
assert cookie.max_age is None
|
|
assert cookie.expires is None
|
|
assert cookie.secure is None
|
|
assert cookie.httponly is None
|
|
assert str(cookie) == "color="
|
|
assert cookie.http_cookie() == "color=;"
|
|
|
|
# 1 cookie with name/value
|
|
s = 'color=blue'
|
|
cookies = Cookie.parse(s)
|
|
assert len(cookies) == 1
|
|
cookie = cookies[0]
|
|
assert cookie.key == 'color'
|
|
assert cookie.value == 'blue'
|
|
assert cookie.domain is None
|
|
assert cookie.path is None
|
|
assert cookie.max_age is None
|
|
assert cookie.expires is None
|
|
assert cookie.secure is None
|
|
assert cookie.httponly is None
|
|
assert str(cookie) == "color=blue"
|
|
assert cookie.http_cookie() == "color=blue;"
|
|
|
|
# 1 cookie with whose value is quoted
|
|
# Use "get by name" utility to extract specific cookie
|
|
s = 'color="blue"'
|
|
cookie = Cookie.get_named_cookie_from_string(s, 'color')
|
|
assert cookie is not None, Cookie
|
|
assert cookie.key == 'color'
|
|
assert cookie.value == 'blue'
|
|
assert cookie.domain is None
|
|
assert cookie.path is None
|
|
assert cookie.max_age is None
|
|
assert cookie.expires is None
|
|
assert cookie.secure is None
|
|
assert cookie.httponly is None
|
|
assert str(cookie) == "color=blue"
|
|
assert cookie.http_cookie() == "color=blue;"
|
|
|
|
# 1 cookie with name/value and domain, path attributes.
|
|
# Change up the whitespace a bit.
|
|
s = 'color =blue; domain= example.com ; path = /toplevel '
|
|
cookies = Cookie.parse(s)
|
|
assert len(cookies) == 1
|
|
cookie = cookies[0]
|
|
assert cookie.key == 'color'
|
|
assert cookie.value == 'blue'
|
|
assert cookie.domain == 'example.com'
|
|
assert cookie.path == '/toplevel'
|
|
assert cookie.max_age is None
|
|
assert cookie.expires is None
|
|
assert cookie.secure is None
|
|
assert cookie.httponly is None
|
|
assert str(cookie) == "color=blue; Domain=example.com; Path=/toplevel"
|
|
assert cookie.http_cookie() == "color=blue;"
|
|
|
|
# 2 cookies, various attributes
|
|
s = 'color=blue; Max-Age=3600; temperature=hot; HttpOnly'
|
|
cookies = Cookie.parse(s)
|
|
assert len(cookies) == 2
|
|
cookie = cookies[0]
|
|
assert cookie.key == 'color'
|
|
assert cookie.value == 'blue'
|
|
assert cookie.domain is None
|
|
assert cookie.path is None
|
|
assert cookie.max_age == 3600
|
|
assert cookie.expires is None
|
|
assert cookie.secure is None
|
|
assert cookie.httponly is None
|
|
assert str(cookie) == "color=blue; Max-Age=3600"
|
|
assert cookie.http_cookie() == "color=blue;"
|
|
cookie = cookies[1]
|
|
assert cookie.key == 'temperature'
|
|
assert cookie.value == 'hot'
|
|
assert cookie.domain is None
|
|
assert cookie.path is None
|
|
assert cookie.max_age is None
|
|
assert cookie.expires is None
|
|
assert cookie.secure is None
|
|
assert cookie.httponly is True
|
|
assert str(cookie) == "temperature=hot; HttpOnly"
|
|
assert cookie.http_cookie() == "temperature=hot;"
|
|
|
|
|
|
class TestExpires:
|
|
|
|
@pytest.fixture(autouse=True)
|
|
def expires_setup(self):
|
|
# Force microseconds to zero because cookie timestamps only have second resolution
|
|
self.now = datetime.datetime.now(
|
|
tz=datetime.timezone.utc).replace(microsecond=0)
|
|
self.now_timestamp = datetime_from_utctimestamp(
|
|
self.now.utctimetuple(), units=1).timestamp()
|
|
self.now_string = email.utils.formatdate(self.now_timestamp, usegmt=True)
|
|
|
|
self.max_age = 3600 # 1 hour
|
|
self.age_expiration = self.now + datetime.timedelta(seconds=self.max_age)
|
|
self.age_timestamp = datetime_from_utctimestamp(
|
|
self.age_expiration.utctimetuple(), units=1).timestamp()
|
|
self.age_string = email.utils.formatdate(self.age_timestamp, usegmt=True)
|
|
|
|
self.expires = self.now + datetime.timedelta(days=1) # 1 day
|
|
self.expires_timestamp = datetime_from_utctimestamp(
|
|
self.expires.utctimetuple(), units=1).timestamp()
|
|
self.expires_string = email.utils.formatdate(self.expires_timestamp, usegmt=True)
|
|
|
|
def test_expires(self):
|
|
# 1 cookie with name/value and no Max-Age and no Expires
|
|
s = 'color=blue;'
|
|
cookies = Cookie.parse(s)
|
|
assert len(cookies) == 1
|
|
cookie = cookies[0]
|
|
# Force timestamp to known value
|
|
cookie.timestamp = self.now
|
|
assert cookie.key == 'color'
|
|
assert cookie.value == 'blue'
|
|
assert cookie.domain is None
|
|
assert cookie.path is None
|
|
assert cookie.max_age is None
|
|
assert cookie.expires is None
|
|
assert cookie.secure is None
|
|
assert cookie.httponly is None
|
|
assert str(cookie) == "color=blue"
|
|
assert cookie.get_expiration() is None
|
|
# Normalize
|
|
assert cookie.normalize_expiration() is None
|
|
assert cookie.max_age is None
|
|
assert cookie.expires is None
|
|
assert str(cookie) == "color=blue"
|
|
|
|
# 1 cookie with name/value and Max-Age
|
|
s = 'color=blue; max-age=%d' % (self.max_age)
|
|
cookies = Cookie.parse(s)
|
|
assert len(cookies) == 1
|
|
cookie = cookies[0]
|
|
# Force timestamp to known value
|
|
cookie.timestamp = self.now
|
|
assert cookie.key == 'color'
|
|
assert cookie.value == 'blue'
|
|
assert cookie.domain is None
|
|
assert cookie.path is None
|
|
assert cookie.max_age == self.max_age
|
|
assert cookie.expires is None
|
|
assert cookie.secure is None
|
|
assert cookie.httponly is None
|
|
assert str(cookie) == "color=blue; Max-Age=%d" % (self.max_age)
|
|
assert cookie.get_expiration() == self.age_expiration
|
|
# Normalize
|
|
assert cookie.normalize_expiration() == self.age_expiration
|
|
assert cookie.max_age is None
|
|
assert cookie.expires == self.age_expiration
|
|
assert str(cookie) == "color=blue; Expires=%s" % (self.age_string)
|
|
|
|
|
|
# 1 cookie with name/value and Expires
|
|
s = 'color=blue; Expires=%s' % (self.expires_string)
|
|
cookies = Cookie.parse(s)
|
|
assert len(cookies) == 1
|
|
cookie = cookies[0]
|
|
# Force timestamp to known value
|
|
cookie.timestamp = self.now
|
|
assert cookie.key == 'color'
|
|
assert cookie.value == 'blue'
|
|
assert cookie.domain is None
|
|
assert cookie.path is None
|
|
assert cookie.max_age is None
|
|
assert cookie.expires == self.expires
|
|
assert cookie.secure is None
|
|
assert cookie.httponly is None
|
|
assert str(cookie) == "color=blue; Expires=%s" % (self.expires_string)
|
|
assert cookie.get_expiration() == self.expires
|
|
# Normalize
|
|
assert cookie.normalize_expiration() == self.expires
|
|
assert cookie.max_age is None
|
|
assert cookie.expires == self.expires
|
|
assert str(cookie) == "color=blue; Expires=%s" % (self.expires_string)
|
|
|
|
# 1 cookie with name/value witht both Max-Age and Expires, Max-Age takes precedence
|
|
s = 'color=blue; Expires=%s; max-age=%d' % (self.expires_string, self.max_age)
|
|
cookies = Cookie.parse(s)
|
|
assert len(cookies) == 1
|
|
cookie = cookies[0]
|
|
# Force timestamp to known value
|
|
cookie.timestamp = self.now
|
|
assert cookie.key == 'color'
|
|
assert cookie.value == 'blue'
|
|
assert cookie.domain is None
|
|
assert cookie.path is None
|
|
assert cookie.max_age == self.max_age
|
|
assert cookie.expires == self.expires
|
|
assert cookie.secure is None
|
|
assert cookie.httponly is None
|
|
expected = "color=blue; Max-Age={}; Expires={}".format(
|
|
self.max_age, self.expires_string)
|
|
assert str(cookie) == expected
|
|
assert cookie.get_expiration() == self.age_expiration
|
|
# Normalize
|
|
assert cookie.normalize_expiration() == self.age_expiration
|
|
assert cookie.max_age is None
|
|
assert cookie.expires == self.age_expiration
|
|
assert str(cookie) == "color=blue; Expires=%s" % (self.age_string)
|
|
|
|
# Verify different types can be assigned to the timestamp and
|
|
# expires attribute.
|
|
|
|
cookie = Cookie('color', 'blue')
|
|
cookie.timestamp = self.now
|
|
assert cookie.timestamp == self.now
|
|
cookie.timestamp = self.now_timestamp
|
|
assert cookie.timestamp == self.now
|
|
cookie.timestamp = self.now_string
|
|
assert cookie.timestamp == self.now
|
|
|
|
assert cookie.expires is None
|
|
|
|
cookie.expires = self.expires
|
|
assert cookie.expires == self.expires
|
|
cookie.expires = self.expires_timestamp
|
|
assert cookie.expires == self.expires
|
|
cookie.expires = self.expires_string
|
|
assert cookie.expires == self.expires
|
|
|
|
|
|
class TestInvalidAttributes:
|
|
def test_invalid(self):
|
|
# Invalid Max-Age
|
|
s = 'color=blue; Max-Age=over-the-hill'
|
|
with pytest.raises(ValueError):
|
|
Cookie.parse(s)
|
|
|
|
cookie = Cookie('color', 'blue')
|
|
with pytest.raises(ValueError):
|
|
cookie.max_age = 'over-the-hill'
|
|
|
|
# Invalid Expires
|
|
s = 'color=blue; Expires=Sun, 06 Xxx 1994 08:49:37 GMT'
|
|
with pytest.raises(ValueError):
|
|
Cookie.parse(s)
|
|
|
|
cookie = Cookie('color', 'blue')
|
|
with pytest.raises(ValueError):
|
|
cookie.expires = 'Sun, 06 Xxx 1994 08:49:37 GMT'
|
|
|
|
|
|
class TestAttributes:
|
|
def test_attributes(self):
|
|
cookie = Cookie('color', 'blue')
|
|
assert cookie.key == 'color'
|
|
assert cookie.value == 'blue'
|
|
assert cookie.domain is None
|
|
assert cookie.path is None
|
|
assert cookie.max_age is None
|
|
assert cookie.expires is None
|
|
assert cookie.secure is None
|
|
assert cookie.httponly is None
|
|
|
|
cookie.domain = 'example.com'
|
|
assert cookie.domain == 'example.com'
|
|
cookie.domain = None
|
|
assert cookie.domain is None
|
|
|
|
cookie.path = '/toplevel'
|
|
assert cookie.path == '/toplevel'
|
|
cookie.path = None
|
|
assert cookie.path is None
|
|
|
|
cookie.max_age = 400
|
|
assert cookie.max_age == 400
|
|
cookie.max_age = None
|
|
assert cookie.max_age is None
|
|
|
|
cookie.expires = 'Sun, 06 Nov 1994 08:49:37 GMT'
|
|
assert cookie.expires == datetime.datetime(
|
|
1994, 11, 6, 8, 49, 37, tzinfo=datetime.timezone.utc)
|
|
cookie.expires = None
|
|
assert cookie.expires is None
|
|
|
|
cookie.secure = True
|
|
assert cookie.secure is True
|
|
assert str(cookie) == "color=blue; Secure"
|
|
cookie.secure = False
|
|
assert cookie.secure is False
|
|
assert str(cookie) == "color=blue"
|
|
cookie.secure = None
|
|
assert cookie.secure is None
|
|
assert str(cookie) == "color=blue"
|
|
|
|
cookie.httponly = True
|
|
assert cookie.httponly is True
|
|
assert str(cookie) == "color=blue; HttpOnly"
|
|
cookie.httponly = False
|
|
assert cookie.httponly is False
|
|
assert str(cookie) == "color=blue"
|
|
cookie.httponly = None
|
|
assert cookie.httponly is None
|
|
assert str(cookie) == "color=blue"
|
|
|
|
|
|
class TestHTTPReturn:
|
|
@pytest.fixture(autouse=True)
|
|
def http_return_setup(self):
|
|
self.url = 'http://www.foo.bar.com/one/two'
|
|
|
|
def test_no_attributes(self):
|
|
cookie = Cookie('color', 'blue')
|
|
assert cookie.http_return_ok(self.url)
|
|
|
|
def test_domain(self):
|
|
cookie = Cookie('color', 'blue', domain='www.foo.bar.com')
|
|
assert cookie.http_return_ok(self.url)
|
|
|
|
cookie = Cookie('color', 'blue', domain='.foo.bar.com')
|
|
assert cookie.http_return_ok(self.url)
|
|
|
|
cookie = Cookie('color', 'blue', domain='.bar.com')
|
|
assert cookie.http_return_ok(self.url)
|
|
|
|
cookie = Cookie('color', 'blue', domain='bar.com')
|
|
with pytest.raises(Cookie.URLMismatch):
|
|
assert cookie.http_return_ok(self.url)
|
|
|
|
cookie = Cookie('color', 'blue', domain='bogus.com')
|
|
with pytest.raises(Cookie.URLMismatch):
|
|
assert cookie.http_return_ok(self.url)
|
|
|
|
cookie = Cookie('color', 'blue', domain='www.foo.bar.com')
|
|
with pytest.raises(Cookie.URLMismatch):
|
|
assert cookie.http_return_ok('http://192.168.1.1/one/two')
|
|
|
|
def test_path(self):
|
|
cookie = Cookie('color', 'blue')
|
|
assert cookie.http_return_ok(self.url)
|
|
|
|
cookie = Cookie('color', 'blue', path='/')
|
|
assert cookie.http_return_ok(self.url)
|
|
|
|
cookie = Cookie('color', 'blue', path='/one')
|
|
assert cookie.http_return_ok(self.url)
|
|
|
|
cookie = Cookie('color', 'blue', path='/oneX')
|
|
with pytest.raises(Cookie.URLMismatch):
|
|
assert cookie.http_return_ok(self.url)
|
|
|
|
def test_expires(self):
|
|
now = datetime.datetime.utcnow().replace(microsecond=0)
|
|
|
|
# expires 1 day from now
|
|
expires = now + datetime.timedelta(days=1)
|
|
|
|
cookie = Cookie('color', 'blue', expires=expires)
|
|
assert cookie.http_return_ok(self.url)
|
|
|
|
# expired 1 day ago
|
|
expires = now + datetime.timedelta(days=-1)
|
|
cookie = Cookie('color', 'blue', expires=expires)
|
|
with pytest.raises(Cookie.Expired):
|
|
assert cookie.http_return_ok(self.url)
|
|
|
|
|
|
def test_httponly(self):
|
|
cookie = Cookie('color', 'blue', httponly=True)
|
|
assert cookie.http_return_ok('http://example.com')
|
|
assert cookie.http_return_ok('https://example.com')
|
|
|
|
with pytest.raises(Cookie.URLMismatch):
|
|
assert cookie.http_return_ok('ftp://example.com')
|
|
|
|
def test_secure(self):
|
|
cookie = Cookie('color', 'blue', secure=True)
|
|
assert cookie.http_return_ok('https://Xexample.com')
|
|
|
|
with pytest.raises(Cookie.URLMismatch):
|
|
assert cookie.http_return_ok('http://Xexample.com')
|
|
|
|
|
|
class TestNormalization:
|
|
@pytest.fixture(autouse=True)
|
|
def normalization_setup(self):
|
|
# Force microseconds to zero because cookie timestamps only have second resolution
|
|
self.now = datetime.datetime.now(
|
|
tz=datetime.timezone.utc).replace(microsecond=0)
|
|
self.now_timestamp = datetime_from_utctimestamp(
|
|
self.now.utctimetuple(), units=1).timestamp()
|
|
self.now_string = email.utils.formatdate(self.now_timestamp, usegmt=True)
|
|
|
|
self.max_age = 3600 # 1 hour
|
|
self.age_expiration = self.now + datetime.timedelta(seconds=self.max_age)
|
|
self.age_timestamp = datetime_from_utctimestamp(
|
|
self.age_expiration.utctimetuple(), units=1).timestamp()
|
|
self.age_string = email.utils.formatdate(self.age_timestamp, usegmt=True)
|
|
|
|
self.expires = self.now + datetime.timedelta(days=1) # 1 day
|
|
self.expires_timestamp = datetime_from_utctimestamp(
|
|
self.expires.utctimetuple(), units=1).timestamp()
|
|
self.expires_string = email.utils.formatdate(self.expires_timestamp, usegmt=True)
|
|
|
|
def test_path_normalization(self):
|
|
assert Cookie.normalize_url_path('') == '/'
|
|
assert Cookie.normalize_url_path('foo') == '/'
|
|
assert Cookie.normalize_url_path('foo/') == '/'
|
|
assert Cookie.normalize_url_path('/foo') == '/'
|
|
assert Cookie.normalize_url_path('/foo/') == '/foo'
|
|
assert Cookie.normalize_url_path('/Foo/bar') == '/foo'
|
|
assert Cookie.normalize_url_path('/foo/baR/') == '/foo/bar'
|
|
|
|
def test_normalization(self):
|
|
cookie = Cookie('color', 'blue', expires=self.expires)
|
|
cookie.timestamp = self.now_timestamp
|
|
|
|
assert cookie.domain is None
|
|
assert cookie.path is None
|
|
|
|
url = 'http://example.COM/foo'
|
|
cookie.normalize(url)
|
|
assert cookie.domain == 'example.com'
|
|
assert cookie.path == '/'
|
|
assert cookie.expires == self.expires
|
|
|
|
cookie = Cookie('color', 'blue', max_age=self.max_age)
|
|
cookie.timestamp = self.now_timestamp
|
|
|
|
assert cookie.domain is None
|
|
assert cookie.path is None
|
|
|
|
url = 'http://example.com/foo/'
|
|
cookie.normalize(url)
|
|
assert cookie.domain == 'example.com'
|
|
assert cookie.path == '/foo'
|
|
assert cookie.expires == self.age_expiration
|
|
|
|
cookie = Cookie('color', 'blue')
|
|
url = 'http://example.com/foo'
|
|
cookie.normalize(url)
|
|
assert cookie.domain == 'example.com'
|
|
assert cookie.path == '/'
|
|
|
|
cookie = Cookie('color', 'blue')
|
|
url = 'http://example.com/foo/bar'
|
|
cookie.normalize(url)
|
|
assert cookie.domain == 'example.com'
|
|
assert cookie.path == '/foo'
|
|
|
|
cookie = Cookie('color', 'blue')
|
|
url = 'http://example.com/foo/bar/'
|
|
cookie.normalize(url)
|
|
assert cookie.domain == 'example.com'
|
|
assert cookie.path == '/foo/bar'
|