From 8e08931b9ffd872a2b5537149a5d3b9f3e9bb5d4 Mon Sep 17 00:00:00 2001 From: Christopher Bartz Date: Fri, 20 Jan 2017 18:04:31 +0100 Subject: ISO 8601 timestamps for tempurl Client-side implementation for ISO 8601 timestamp support of tempurl middleware. Please see https://review.openstack.org/#/c/422679/ Change-Id: I76da28b48948475ec1bae5258e0b39a316553fb7 --- tests/unit/test_shell.py | 80 +++++++++++++++++++++++++++++++++++++++++--- tests/unit/test_utils.py | 87 ++++++++++++++++++++++++++++++++++++++++++------ 2 files changed, 151 insertions(+), 16 deletions(-) (limited to 'tests') diff --git a/tests/unit/test_shell.py b/tests/unit/test_shell.py index f7e9c1a..2fe0139 100644 --- a/tests/unit/test_shell.py +++ b/tests/unit/test_shell.py @@ -23,6 +23,7 @@ import os import tempfile import unittest import textwrap +from time import localtime, mktime, strftime, strptime from requests.packages.urllib3.exceptions import InsecureRequestWarning import six @@ -36,7 +37,9 @@ from os.path import basename, dirname from .utils import ( CaptureOutput, fake_get_auth_keystone, _make_fake_import_keystone_client, FakeKeystone, StubResponse, MockHttpTest) -from swiftclient.utils import EMPTY_ETAG +from swiftclient.utils import ( + EMPTY_ETAG, EXPIRES_ISO8601_FORMAT, + SHORT_EXPIRES_ISO8601_FORMAT, TIME_ERRMSG) if six.PY2: @@ -1550,7 +1553,7 @@ class TestShell(unittest.TestCase): swiftclient.shell.main(argv) temp_url.assert_called_with( '/v1/AUTH_account/c/o', "60", 'secret_key', 'GET', absolute=False, - prefix=False) + iso8601=False, prefix=False) @mock.patch('swiftclient.shell.generate_temp_url', return_value='') def test_temp_url_prefix_based(self, temp_url): @@ -1559,7 +1562,28 @@ class TestShell(unittest.TestCase): swiftclient.shell.main(argv) temp_url.assert_called_with( '/v1/AUTH_account/c/', "60", 'secret_key', 'GET', absolute=False, - prefix=True) + iso8601=False, prefix=True) + + @mock.patch('swiftclient.shell.generate_temp_url', return_value='') + def test_temp_url_iso8601_in(self, temp_url): + dates = ('1970-01-01T00:01:00Z', '1970-01-01T00:01:00', + '1970-01-01') + for d in dates: + argv = ["", "tempurl", "GET", d, "/v1/AUTH_account/c/", + "secret_key"] + swiftclient.shell.main(argv) + temp_url.assert_called_with( + '/v1/AUTH_account/c/', d, 'secret_key', 'GET', absolute=False, + iso8601=False, prefix=False) + + @mock.patch('swiftclient.shell.generate_temp_url', return_value='') + def test_temp_url_iso8601_out(self, temp_url): + argv = ["", "tempurl", "GET", "60", "/v1/AUTH_account/c/", + "secret_key", "--iso8601"] + swiftclient.shell.main(argv) + temp_url.assert_called_with( + '/v1/AUTH_account/c/', "60", 'secret_key', 'GET', absolute=False, + iso8601=True, prefix=False) @mock.patch('swiftclient.shell.generate_temp_url', return_value='') def test_absolute_expiry_temp_url(self, temp_url): @@ -1568,7 +1592,7 @@ class TestShell(unittest.TestCase): swiftclient.shell.main(argv) temp_url.assert_called_with( '/v1/AUTH_account/c/o', "60", 'secret_key', 'GET', absolute=True, - prefix=False) + iso8601=False, prefix=False) def test_temp_url_output(self): argv = ["", "tempurl", "GET", "60", "/v1/a/c/o", @@ -1595,6 +1619,42 @@ class TestShell(unittest.TestCase): "&temp_url_prefix=\n" % sig) self.assertEqual(expected, output.out) + argv = ["", "tempurl", "GET", "60", "/v1/a/c/", + "secret_key", "--absolute", "--prefix", '--iso8601'] + with CaptureOutput(suppress_systemexit=True) as output: + swiftclient.shell.main(argv) + sig = '00008c4be1573ba74fc2ab9bce02e3a93d04b349' + expires = '1970-01-01T00:01:00Z' + expected = ("/v1/a/c/?temp_url_sig=%s&temp_url_expires=%s" + "&temp_url_prefix=\n" % (sig, expires)) + self.assertEqual(expected, output.out) + + dates = ("1970-01-01T00:01:00Z", + strftime(EXPIRES_ISO8601_FORMAT[:-1], localtime(60))) + for d in dates: + argv = ["", "tempurl", "GET", d, "/v1/a/c/o", + "secret_key"] + with CaptureOutput(suppress_systemexit=True) as output: + swiftclient.shell.main(argv) + sig = "63bc77a473a1c2ce956548cacf916f292eb9eac3" + expected = "/v1/a/c/o?temp_url_sig=%s&temp_url_expires=60\n" % sig + self.assertEqual(expected, output.out) + + ts = str(int( + mktime(strptime('2005-05-01', SHORT_EXPIRES_ISO8601_FORMAT)))) + + argv = ["", "tempurl", "GET", ts, "/v1/a/c/", + "secret_key", "--absolute"] + with CaptureOutput(suppress_systemexit=True) as output: + swiftclient.shell.main(argv) + expected = output.out + + argv = ["", "tempurl", "GET", '2005-05-01', "/v1/a/c/", + "secret_key", "--absolute"] + with CaptureOutput(suppress_systemexit=True) as output: + swiftclient.shell.main(argv) + self.assertEqual(expected, output.out) + def test_temp_url_error_output(self): expected = 'path must be full path to an object e.g. /v1/a/c/o\n' for bad_path in ('/v1/a/c', 'v1/a/c/o', '/v1/a/c/', '/v1/a//o', @@ -1614,7 +1674,17 @@ class TestShell(unittest.TestCase): swiftclient.shell.main(argv) self.assertEqual(expected, output.err, 'Expected %r but got %r for path %r' % - (expected, output.err, bad_path)) + (expected, output.err, '/v1/a/c')) + + expected = TIME_ERRMSG + '\n' + for bad_time in ('not_an_int', '-1', '2015-05', '2015-05-01T01:00'): + argv = ["", "tempurl", "GET", bad_time, '/v1/a/c/o', + "secret_key", "--absolute"] + with CaptureOutput(suppress_systemexit=True) as output: + swiftclient.shell.main(argv) + self.assertEqual(expected, output.err, + 'Expected %r but got %r for time %r' % + (expected, output.err, bad_time)) @mock.patch('swiftclient.service.Connection') def test_capabilities(self, connection): diff --git a/tests/unit/test_utils.py b/tests/unit/test_utils.py index c5961e8..adead00 100644 --- a/tests/unit/test_utils.py +++ b/tests/unit/test_utils.py @@ -18,6 +18,7 @@ import unittest import mock import six import tempfile +from time import gmtime, localtime, mktime, strftime, strptime from hashlib import md5, sha1 from swiftclient import utils as u @@ -150,6 +151,67 @@ class TestTempURL(unittest.TestCase): ]) self.assertIsInstance(url, type(self.url)) + @mock.patch('hmac.HMAC') + def test_generate_temp_url_iso8601_argument(self, hmac_mock): + hmac_mock().hexdigest.return_value = 'temp_url_signature' + url = u.generate_temp_url(self.url, '2014-05-13T17:53:20Z', + self.key, self.method) + self.assertEqual(url, self.expected_url) + + # Don't care about absolute arg. + url = u.generate_temp_url(self.url, '2014-05-13T17:53:20Z', + self.key, self.method, absolute=True) + self.assertEqual(url, self.expected_url) + + lt = localtime() + expires = strftime(u.EXPIRES_ISO8601_FORMAT[:-1], lt) + + if not isinstance(self.expected_url, six.string_types): + expected_url = self.expected_url.replace( + b'1400003600', bytes(str(int(mktime(lt))), encoding='ascii')) + else: + expected_url = self.expected_url.replace( + '1400003600', str(int(mktime(lt)))) + url = u.generate_temp_url(self.url, expires, + self.key, self.method) + self.assertEqual(url, expected_url) + + expires = strftime(u.SHORT_EXPIRES_ISO8601_FORMAT, lt) + lt = strptime(expires, u.SHORT_EXPIRES_ISO8601_FORMAT) + + if not isinstance(self.expected_url, six.string_types): + expected_url = self.expected_url.replace( + b'1400003600', bytes(str(int(mktime(lt))), encoding='ascii')) + else: + expected_url = self.expected_url.replace( + '1400003600', str(int(mktime(lt)))) + url = u.generate_temp_url(self.url, expires, + self.key, self.method) + self.assertEqual(url, expected_url) + + @mock.patch('hmac.HMAC') + @mock.patch('time.time', return_value=1400000000) + def test_generate_temp_url_iso8601_output(self, time_mock, hmac_mock): + hmac_mock().hexdigest.return_value = 'temp_url_signature' + url = u.generate_temp_url(self.url, self.seconds, + self.key, self.method, + iso8601=True) + key = self.key + if not isinstance(key, six.binary_type): + key = key.encode('utf-8') + + expires = strftime(u.EXPIRES_ISO8601_FORMAT, gmtime(1400003600)) + if not isinstance(self.url, six.string_types): + self.assertTrue(url.endswith(bytes(expires, 'utf-8'))) + else: + self.assertTrue(url.endswith(expires)) + self.assertEqual(hmac_mock.mock_calls, [ + mock.call(), + mock.call(key, self.expected_body, sha1), + mock.call().hexdigest(), + ]) + self.assertIsInstance(url, type(self.url)) + @mock.patch('hmac.HMAC') @mock.patch('time.time', return_value=1400000000) def test_generate_temp_url_prefix(self, time_mock, hmac_mock): @@ -198,31 +260,34 @@ class TestTempURL(unittest.TestCase): absolute=True) self.assertEqual(url, expected_url) - def test_generate_temp_url_bad_seconds(self): + def test_generate_temp_url_bad_time(self): with self.assertRaises(ValueError) as exc_manager: u.generate_temp_url(self.url, 'not_an_int', self.key, self.method) - self.assertEqual(exc_manager.exception.args[0], - 'seconds must be a whole number') + self.assertEqual(exc_manager.exception.args[0], u.TIME_ERRMSG) with self.assertRaises(ValueError) as exc_manager: u.generate_temp_url(self.url, -1, self.key, self.method) - self.assertEqual(exc_manager.exception.args[0], - 'seconds must be a whole number') + self.assertEqual(exc_manager.exception.args[0], u.TIME_ERRMSG) with self.assertRaises(ValueError) as exc_manager: u.generate_temp_url(self.url, 1.1, self.key, self.method) - self.assertEqual(exc_manager.exception.args[0], - 'seconds must be a whole number') + self.assertEqual(exc_manager.exception.args[0], u.TIME_ERRMSG) with self.assertRaises(ValueError) as exc_manager: u.generate_temp_url(self.url, '-1', self.key, self.method) - self.assertEqual(exc_manager.exception.args[0], - 'seconds must be a whole number') + self.assertEqual(exc_manager.exception.args[0], u.TIME_ERRMSG) with self.assertRaises(ValueError) as exc_manager: u.generate_temp_url(self.url, '1.1', self.key, self.method) - self.assertEqual(exc_manager.exception.args[0], - 'seconds must be a whole number') + self.assertEqual(exc_manager.exception.args[0], u.TIME_ERRMSG) + with self.assertRaises(ValueError) as exc_manager: + u.generate_temp_url(self.url, '2015-05', self.key, self.method) + self.assertEqual(exc_manager.exception.args[0], u.TIME_ERRMSG) + + with self.assertRaises(ValueError) as exc_manager: + u.generate_temp_url( + self.url, '2015-05-01T01:00', self.key, self.method) + self.assertEqual(exc_manager.exception.args[0], u.TIME_ERRMSG) def test_generate_temp_url_bad_path(self): with self.assertRaises(ValueError) as exc_manager: -- cgit v1.2.1