Merge "Add some bash helpers for auth stuff"

This commit is contained in:
Jenkins 2015-07-11 06:41:45 +00:00 committed by Gerrit Code Review
commit 605ec92507
3 changed files with 156 additions and 6 deletions
swiftclient
tests/unit

@ -31,14 +31,19 @@ from swiftclient.utils import config_true_value, generate_temp_url, prt_bytes
from swiftclient.multithreading import OutputManager
from swiftclient.exceptions import ClientException
from swiftclient import __version__ as client_version
from swiftclient.service import SwiftService, SwiftError, SwiftUploadObject
from swiftclient.service import SwiftService, SwiftError, \
SwiftUploadObject, get_conn
from swiftclient.command_helpers import print_account_stats, \
print_container_stats, print_object_stats
try:
from shlex import quote as sh_quote
except ImportError:
from pipes import quote as sh_quote
BASENAME = 'swift'
commands = ('delete', 'download', 'list', 'post',
'stat', 'upload', 'capabilities', 'info', 'tempurl')
commands = ('delete', 'download', 'list', 'post', 'stat', 'upload',
'capabilities', 'info', 'tempurl', 'auth')
def immediate_exit(signum, frame):
@ -930,6 +935,46 @@ def st_capabilities(parser, args, output_manager):
st_info = st_capabilities
st_auth_help = '''
Display auth related authentication variables in shell friendly format.
Commands to run to export storage url and auth token into
OS_STORAGE_URL and OS_AUTH_TOKEN:
swift auth
Commands to append to a runcom file (e.g. ~/.bashrc, /etc/profile) for
automatic authentication:
swift auth -v -U test:tester -K testing \
-A http://localhost:8080/auth/v1.0
'''.strip('\n')
def st_auth(parser, args, thread_manager):
(options, args) = parse_args(parser, args)
_opts = vars(options)
if options.verbose > 1:
if options.auth_version in ('1', '1.0'):
print('export ST_AUTH=%s' % sh_quote(options.auth))
print('export ST_USER=%s' % sh_quote(options.user))
print('export ST_KEY=%s' % sh_quote(options.key))
else:
print('export OS_IDENTITY_API_VERSION=%s' % sh_quote(
options.auth_version))
print('export OS_AUTH_VERSION=%s' % sh_quote(options.auth_version))
print('export OS_AUTH_URL=%s' % sh_quote(options.auth))
for k, v in sorted(_opts.items()):
if v and k.startswith('os_') and \
k not in ('os_auth_url', 'os_options'):
print('export %s=%s' % (k.upper(), sh_quote(v)))
else:
conn = get_conn(_opts)
url, token = conn.get_auth()
print('export OS_STORAGE_URL=%s' % sh_quote(url))
print('export OS_AUTH_TOKEN=%s' % sh_quote(token))
st_tempurl_options = '<method> <seconds> <path> <key>'
@ -1098,7 +1143,8 @@ Positional arguments:
or object.
upload Uploads files or directories to the given container.
capabilities List cluster capabilities.
tempurl Create a temporary URL
tempurl Create a temporary URL.
auth Display auth related environment variables.
Examples:
%%prog download --help

@ -19,8 +19,10 @@ import mock
import os
import tempfile
import unittest
import textwrap
from testtools import ExpectedException
import six
import swiftclient
@ -46,6 +48,11 @@ mocked_os_environ = {
'ST_USER': 'test:tester',
'ST_KEY': 'testing'
}
clean_os_environ = {}
environ_prefixes = ('ST_', 'OS_')
for key in os.environ:
if any(key.startswith(m) for m in environ_prefixes):
clean_os_environ[key] = ''
clean_os_environ = {}
environ_prefixes = ('ST_', 'OS_')
@ -1554,6 +1561,101 @@ class TestAuth(MockHttpTest):
}),
])
def test_auth(self):
headers = {
'x-auth-token': 'AUTH_tk5b6b12',
'x-storage-url': 'https://swift.storage.example.com/v1/AUTH_test',
}
mock_resp = self.fake_http_connection(200, headers=headers)
with mock.patch('swiftclient.client.http_connection', new=mock_resp):
stdout = six.StringIO()
with mock.patch('sys.stdout', new=stdout):
argv = [
'',
'auth',
'--auth', 'https://swift.storage.example.com/auth/v1.0',
'--user', 'test:tester', '--key', 'testing',
]
swiftclient.shell.main(argv)
expected = """
export OS_STORAGE_URL=https://swift.storage.example.com/v1/AUTH_test
export OS_AUTH_TOKEN=AUTH_tk5b6b12
"""
self.assertEquals(textwrap.dedent(expected).lstrip(),
stdout.getvalue())
def test_auth_verbose(self):
with mock.patch('swiftclient.client.http_connection') as mock_conn:
stdout = six.StringIO()
with mock.patch('sys.stdout', new=stdout):
argv = [
'',
'auth',
'--auth', 'https://swift.storage.example.com/auth/v1.0',
'--user', 'test:tester', '--key', 'te$tin&',
'--verbose',
]
swiftclient.shell.main(argv)
expected = """
export ST_AUTH=https://swift.storage.example.com/auth/v1.0
export ST_USER=test:tester
export ST_KEY='te$tin&'
"""
self.assertEquals(textwrap.dedent(expected).lstrip(),
stdout.getvalue())
self.assertEqual([], mock_conn.mock_calls)
def test_auth_v2(self):
os_options = {'tenant_name': 'demo'}
with mock.patch('swiftclient.client.get_auth_keystone',
new=fake_get_auth_keystone(os_options)):
stdout = six.StringIO()
with mock.patch('sys.stdout', new=stdout):
argv = [
'',
'auth', '-V2',
'--auth', 'https://keystone.example.com/v2.0/',
'--os-tenant-name', 'demo',
'--os-username', 'demo', '--os-password', 'admin',
]
swiftclient.shell.main(argv)
expected = """
export OS_STORAGE_URL=http://url/
export OS_AUTH_TOKEN=token
"""
self.assertEquals(textwrap.dedent(expected).lstrip(),
stdout.getvalue())
def test_auth_verbose_v2(self):
with mock.patch('swiftclient.client.get_auth_keystone') \
as mock_keystone:
stdout = six.StringIO()
with mock.patch('sys.stdout', new=stdout):
argv = [
'',
'auth', '-V2',
'--auth', 'https://keystone.example.com/v2.0/',
'--os-tenant-name', 'demo',
'--os-username', 'demo', '--os-password', '$eKr3t',
'--verbose',
]
swiftclient.shell.main(argv)
expected = """
export OS_IDENTITY_API_VERSION=2.0
export OS_AUTH_VERSION=2.0
export OS_AUTH_URL=https://keystone.example.com/v2.0/
export OS_PASSWORD='$eKr3t'
export OS_TENANT_NAME=demo
export OS_USERNAME=demo
"""
self.assertEquals(textwrap.dedent(expected).lstrip(),
stdout.getvalue())
self.assertEqual([], mock_keystone.mock_calls)
class TestCrossAccountObjectAccess(TestBase, MockHttpTest):
"""

@ -38,8 +38,10 @@ def fake_get_auth_keystone(expected_os_options=None, exc=None,
if exc:
raise exc('test')
# TODO: some way to require auth_url, user and key?
if expected_os_options and actual_os_options != expected_os_options:
return "", None
if expected_os_options:
for key, value in actual_os_options.items():
if value and value != expected_os_options.get(key):
return "", None
if 'required_kwargs' in kwargs:
for k, v in kwargs['required_kwargs'].items():
if v != actual_kwargs.get(k):