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.
|
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
|
||||||
|
@ -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)
|
||||||
|
|
||||||
|
|
||||||
|
@ -65,8 +65,8 @@ 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.
|
||||||
|
|
||||||
:param path: The full path to the Swift object. Example:
|
: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:
|
if seconds < 0:
|
||||||
raise ValueError('seconds must be a positive integer')
|
raise ValueError('seconds must be a positive integer')
|
||||||
try:
|
try:
|
||||||
expiration = int(time.time() + seconds)
|
if not absolute:
|
||||||
|
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')
|
||||||
|
|
||||||
|
@ -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):
|
||||||
|
@ -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,
|
||||||
|
Loading…
x
Reference in New Issue
Block a user