absolute expiry option for tempURL generation
The `tempurl` subcommand's second positional argument is called `seconds` and has heretofore interpreted as the number of seconds for which the tempURL should be valid, counting from the moment of running the command. This is indeed a common, if not the most common, use-case. But some users, occasionally, might want to generate a tempURL that expires at some particular ("absolute") time, rather than a particular amount of time relative to the moment of happening to run the command. (One might make an analogy to the way in which Swift's expiring object support supports an `X-Delete-At` header in addition to `X-Delete-After`—and it's the former that must be regarded as ontologically prior.) Thus, this commit adds an `--absolute` optional argument to the `tempurl` subcommand; if present, the `seconds` argument will be interpreted as a Unix timestamp of when the tempURL should be expire, rather than a duration for which the tempURL should be valid starting from "now". Change-Id: If9ded96f2799800958d5063127f3de812f50ef06
This commit is contained in:
parent
93666bb84a
commit
52d39bebc1
@ -104,12 +104,14 @@ is not provided the storage-url retrieved after authentication is used as
|
||||
proxy-url.
|
||||
.RE
|
||||
|
||||
\fBtempurl\fR method seconds path key
|
||||
\fBtempurl\fR \fImethod\fR \fIseconds\fR \fIpath\fR \fIkey\fR [\fI--absolute\fR]
|
||||
.RS 4
|
||||
Generates a temporary URL allowing unauthenticated access to the Swift object at
|
||||
the given path, using the given HTTP method, for the given number of seconds,
|
||||
using the given TempURL key. \fBExample\fR: tempurl GET 86400
|
||||
/v1/AUTH_foo/bar_container/quux.md my_secret_tempurl_key
|
||||
Generates a temporary URL allowing unauthenticated access to the Swift object
|
||||
at the given path, using the given HTTP method, for the given number of
|
||||
seconds, using the given TempURL key. If optional --absolute argument is
|
||||
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
|
||||
|
||||
.SH OPTIONS
|
||||
|
@ -1013,17 +1013,30 @@ Generates a temporary URL for a Swift object.
|
||||
Positional arguments:
|
||||
<method> An HTTP method to allow for this temporary URL.
|
||||
Usually 'GET' or 'PUT'.
|
||||
<seconds> The amount of time in seconds the temporary URL will
|
||||
be valid for.
|
||||
<seconds> The amount of time in seconds the temporary URL will be
|
||||
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:
|
||||
/v1/AUTH_account/c/o.
|
||||
<key> The secret temporary URL key set on the Swift cluster.
|
||||
To set a key, run \'swift post -m
|
||||
"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')
|
||||
|
||||
|
||||
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)
|
||||
args = args[1:]
|
||||
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 '
|
||||
'tempurl specified, possibly an error' %
|
||||
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)
|
||||
|
||||
|
||||
|
@ -65,8 +65,8 @@ def prt_bytes(bytes, human_flag):
|
||||
return bytes
|
||||
|
||||
|
||||
def generate_temp_url(path, seconds, key, method):
|
||||
""" Generates a temporary URL that gives unauthenticated access to the
|
||||
def generate_temp_url(path, seconds, key, method, absolute=False):
|
||||
"""Generates a temporary URL that gives unauthenticated access to the
|
||||
Swift object.
|
||||
|
||||
:param path: The full path to the Swift object. Example:
|
||||
@ -85,7 +85,10 @@ def generate_temp_url(path, seconds, key, method):
|
||||
if seconds < 0:
|
||||
raise ValueError('seconds must be a positive integer')
|
||||
try:
|
||||
expiration = int(time.time() + seconds)
|
||||
if not absolute:
|
||||
expiration = int(time.time() + seconds)
|
||||
else:
|
||||
expiration = int(seconds)
|
||||
except TypeError:
|
||||
raise TypeError('seconds must be an integer')
|
||||
|
||||
|
@ -922,15 +922,21 @@ class TestShell(unittest.TestCase):
|
||||
self.assertTrue(output.err != '')
|
||||
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):
|
||||
argv = ["", "tempurl", "GET", "60", "/v1/AUTH_account/c/o",
|
||||
"secret_key"
|
||||
]
|
||||
temp_url.return_value = ""
|
||||
"secret_key"]
|
||||
swiftclient.shell.main(argv)
|
||||
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')
|
||||
def test_capabilities(self, connection):
|
||||
|
@ -132,11 +132,9 @@ class TestTempURL(testtools.TestCase):
|
||||
self.key = 'correcthorsebatterystaple'
|
||||
self.method = 'GET'
|
||||
|
||||
@mock.patch('hmac.HMAC.hexdigest')
|
||||
@mock.patch('time.time')
|
||||
@mock.patch('hmac.HMAC.hexdigest', return_value='temp_url_signature')
|
||||
@mock.patch('time.time', return_value=1400000000)
|
||||
def test_generate_temp_url(self, time_mock, hmac_mock):
|
||||
time_mock.return_value = 1400000000
|
||||
hmac_mock.return_value = 'temp_url_signature'
|
||||
expected_url = (
|
||||
'/v1/AUTH_account/c/o?'
|
||||
'temp_url_sig=temp_url_signature&'
|
||||
@ -145,6 +143,15 @@ class TestTempURL(testtools.TestCase):
|
||||
self.method)
|
||||
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):
|
||||
self.assertRaises(TypeError,
|
||||
u.generate_temp_url,
|
||||
|
Loading…
Reference in New Issue
Block a user