Merge "absolute expiry option for tempURL generation"

This commit is contained in:
Jenkins
2015-09-05 20:16:38 +00:00
committed by Gerrit Code Review
5 changed files with 52 additions and 20 deletions

View File

@@ -104,12 +104,14 @@ is not provided the storage-url retrieved after authentication is used as
proxy-url. proxy-url.
.RE .RE
\fBtempurl\fR method seconds path key \fBtempurl\fR \fImethod\fR \fIseconds\fR \fIpath\fR \fIkey\fR [\fI--absolute\fR]
.RS 4 .RS 4
Generates a temporary URL allowing unauthenticated access to the Swift object at Generates a temporary URL allowing unauthenticated access to the Swift object
the given path, using the given HTTP method, for the given number of seconds, at the given path, using the given HTTP method, for the given number of
using the given TempURL key. \fBExample\fR: tempurl GET 86400 seconds, using the given TempURL key. If optional --absolute argument is
/v1/AUTH_foo/bar_container/quux.md my_secret_tempurl_key provided, seconds is instead interpreted as a Unix timestamp at which the URL
should expire. \fBExample\fR: tempurl GET $(date -d "Jan 1 2016" +%s)
/v1/AUTH_foo/bar_container/quux.md my_secret_tempurl_key --absolute
.RE .RE
.SH OPTIONS .SH OPTIONS

View File

@@ -1013,17 +1013,30 @@ Generates a temporary URL for a Swift object.
Positional arguments: Positional arguments:
<method> An HTTP method to allow for this temporary URL. <method> An HTTP method to allow for this temporary URL.
Usually 'GET' or 'PUT'. Usually 'GET' or 'PUT'.
<seconds> The amount of time in seconds the temporary URL will <seconds> The amount of time in seconds the temporary URL will be
be valid for. valid for; or, if --absolute is passed, the Unix
timestamp when the temporary URL will expire.
<path> The full path to the Swift object. Example: <path> The full path to the Swift object. Example:
/v1/AUTH_account/c/o. /v1/AUTH_account/c/o.
<key> The secret temporary URL key set on the Swift cluster. <key> The secret temporary URL key set on the Swift cluster.
To set a key, run \'swift post -m To set a key, run \'swift post -m
"Temp-URL-Key:b3968d0207b54ece87cccc06515a89d4"\' "Temp-URL-Key:b3968d0207b54ece87cccc06515a89d4"\'
Optional arguments:
--absolute Interpet the <seconds> positional argument as a Unix
timestamp rather than a number of seconds in the
future.
'''.strip('\n') '''.strip('\n')
def st_tempurl(parser, args, thread_manager): def st_tempurl(parser, args, thread_manager):
parser.add_option(
'--absolute', action='store_true',
dest='absolute_expiry', default=False,
help=("If present, seconds argument will be interpreted as a Unix "
"timestamp representing when the tempURL should expire, rather "
"than an offset from the current time")
)
(options, args) = parse_args(parser, args) (options, args) = parse_args(parser, args)
args = args[1:] args = args[1:]
if len(args) < 4: if len(args) < 4:
@@ -1040,7 +1053,8 @@ def st_tempurl(parser, args, thread_manager):
thread_manager.print_msg('WARNING: Non default HTTP method %s for ' thread_manager.print_msg('WARNING: Non default HTTP method %s for '
'tempurl specified, possibly an error' % 'tempurl specified, possibly an error' %
method.upper()) method.upper())
url = generate_temp_url(path, seconds, key, method) url = generate_temp_url(path, seconds, key, method,
absolute=options.absolute_expiry)
thread_manager.print_msg(url) thread_manager.print_msg(url)

View File

@@ -65,7 +65,7 @@ def prt_bytes(bytes, human_flag):
return bytes return bytes
def generate_temp_url(path, seconds, key, method): def generate_temp_url(path, seconds, key, method, absolute=False):
"""Generates a temporary URL that gives unauthenticated access to the """Generates a temporary URL that gives unauthenticated access to the
Swift object. Swift object.
@@ -85,7 +85,10 @@ def generate_temp_url(path, seconds, key, method):
if seconds < 0: if seconds < 0:
raise ValueError('seconds must be a positive integer') raise ValueError('seconds must be a positive integer')
try: try:
if not absolute:
expiration = int(time.time() + seconds) expiration = int(time.time() + seconds)
else:
expiration = int(seconds)
except TypeError: except TypeError:
raise TypeError('seconds must be an integer') raise TypeError('seconds must be an integer')

View File

@@ -922,15 +922,21 @@ class TestShell(unittest.TestCase):
self.assertTrue(output.err != '') self.assertTrue(output.err != '')
self.assertTrue(output.err.startswith('Usage')) self.assertTrue(output.err.startswith('Usage'))
@mock.patch('swiftclient.shell.generate_temp_url') @mock.patch('swiftclient.shell.generate_temp_url', return_value='')
def test_temp_url(self, temp_url): def test_temp_url(self, temp_url):
argv = ["", "tempurl", "GET", "60", "/v1/AUTH_account/c/o", argv = ["", "tempurl", "GET", "60", "/v1/AUTH_account/c/o",
"secret_key" "secret_key"]
]
temp_url.return_value = ""
swiftclient.shell.main(argv) swiftclient.shell.main(argv)
temp_url.assert_called_with( temp_url.assert_called_with(
'/v1/AUTH_account/c/o', 60, 'secret_key', 'GET') '/v1/AUTH_account/c/o', 60, 'secret_key', 'GET', absolute=False)
@mock.patch('swiftclient.shell.generate_temp_url', return_value='')
def test_absolute_expiry_temp_url(self, temp_url):
argv = ["", "tempurl", "GET", "60", "/v1/AUTH_account/c/o",
"secret_key", "--absolute"]
swiftclient.shell.main(argv)
temp_url.assert_called_with(
'/v1/AUTH_account/c/o', 60, 'secret_key', 'GET', absolute=True)
@mock.patch('swiftclient.service.Connection') @mock.patch('swiftclient.service.Connection')
def test_capabilities(self, connection): def test_capabilities(self, connection):

View File

@@ -132,11 +132,9 @@ class TestTempURL(testtools.TestCase):
self.key = 'correcthorsebatterystaple' self.key = 'correcthorsebatterystaple'
self.method = 'GET' self.method = 'GET'
@mock.patch('hmac.HMAC.hexdigest') @mock.patch('hmac.HMAC.hexdigest', return_value='temp_url_signature')
@mock.patch('time.time') @mock.patch('time.time', return_value=1400000000)
def test_generate_temp_url(self, time_mock, hmac_mock): def test_generate_temp_url(self, time_mock, hmac_mock):
time_mock.return_value = 1400000000
hmac_mock.return_value = 'temp_url_signature'
expected_url = ( expected_url = (
'/v1/AUTH_account/c/o?' '/v1/AUTH_account/c/o?'
'temp_url_sig=temp_url_signature&' 'temp_url_sig=temp_url_signature&'
@@ -145,6 +143,15 @@ class TestTempURL(testtools.TestCase):
self.method) self.method)
self.assertEqual(url, expected_url) self.assertEqual(url, expected_url)
@mock.patch('hmac.HMAC.hexdigest', return_value="temp_url_signature")
def test_generate_absolute_expiry_temp_url(self, hmac_mock):
expected_url = ('/v1/AUTH_account/c/o?'
'temp_url_sig=temp_url_signature&'
'temp_url_expires=2146636800')
url = u.generate_temp_url(self.url, 2146636800, self.key, self.method,
absolute=True)
self.assertEqual(url, expected_url)
def test_generate_temp_url_bad_seconds(self): def test_generate_temp_url_bad_seconds(self):
self.assertRaises(TypeError, self.assertRaises(TypeError,
u.generate_temp_url, u.generate_temp_url,