diff options
author | Charles Hsu <charles0126@gmail.com> | 2019-12-18 00:32:36 +0800 |
---|---|---|
committer | Charles Hsu <charles0126@gmail.com> | 2020-04-16 12:41:04 +0800 |
commit | 02b637cdca6963e8dcab5170422347df99606f92 (patch) | |
tree | e245ccc06d484fbc6981deff47cf3f50018d8d52 /swiftclient | |
parent | c36616292fa27d5da956d58fcb20470e04fd9946 (diff) | |
download | python-swiftclient-02b637cdca6963e8dcab5170422347df99606f92.tar.gz |
Support v3 application credentials auth.
Use keystoneauth1 application credential plugin and session to fetch
a token and endpoint catalog url.
$ swift --os-auth-url http://172.16.1.2:5000/v3 --auth-version 3\
--os-application-credential-id THE_ID \
--os-application-credential-secret THE_SECRET \
--os-auth-type v3applicationcredential auth
Change-Id: I9190e5e7e24b6a741970fa0d0ac792deccf73d25
Closes-Bug: 1843901
Closes-Bug: 1856635
Diffstat (limited to 'swiftclient')
-rw-r--r-- | swiftclient/client.py | 59 | ||||
-rw-r--r-- | swiftclient/service.py | 13 | ||||
-rwxr-xr-x | swiftclient/shell.py | 54 |
3 files changed, 112 insertions, 14 deletions
diff --git a/swiftclient/client.py b/swiftclient/client.py index 449b6cd..ee85a14 100644 --- a/swiftclient/client.py +++ b/swiftclient/client.py @@ -70,6 +70,9 @@ except ImportError: pass try: from keystoneclient.v3 import client as ksclient_v3 + from keystoneauth1.identity import v3 + from keystoneauth1 import session + from keystoneauth1 import exceptions as ksauthexceptions except ImportError: pass @@ -615,6 +618,46 @@ Auth versions 2.0 and 3 require python-keystoneclient, install it or use Auth version 1.0 which requires ST_AUTH, ST_USER, and ST_KEY environment variables to be set or overridden with -A, -U, or -K.''') + filter_kwargs = {} + service_type = os_options.get('service_type') or 'object-store' + endpoint_type = os_options.get('endpoint_type') or 'publicURL' + if os_options.get('region_name'): + filter_kwargs['attr'] = 'region' + filter_kwargs['filter_value'] = os_options['region_name'] + + if os_options.get('auth_type') == 'v3applicationcredential': + try: + v3 + except NameError: + raise ClientException('Auth v3applicationcredential requires ' + 'python-keystoneclient>=2.0.0') + + try: + auth = v3.ApplicationCredential( + auth_url=auth_url, + application_credential_secret=os_options.get( + 'application_credential_secret'), + application_credential_id=os_options.get( + 'application_credential_id')) + sses = session.Session(auth=auth) + token = sses.get_token() + except ksauthexceptions.Unauthorized: + msg = 'Unauthorized. Check application credential id and secret.' + raise ClientException(msg) + except ksauthexceptions.AuthorizationFailure as err: + raise ClientException('Authorization Failure. %s' % err) + + try: + endpoint = sses.get_endpoint_data(service_type=service_type, + endpoint_type=endpoint_type, + **filter_kwargs) + + return endpoint.catalog_url, token + except ksauthexceptions.EndpointNotFound: + raise ClientException( + 'Endpoint for %s not found - ' + 'have you specified a region?' % service_type) + try: _ksclient = ksclient.Client( username=user, @@ -642,13 +685,8 @@ variables to be set or overridden with -A, -U, or -K.''') raise ClientException(msg) except ksexceptions.AuthorizationFailure as err: raise ClientException('Authorization Failure. %s' % err) - service_type = os_options.get('service_type') or 'object-store' - endpoint_type = os_options.get('endpoint_type') or 'publicURL' + try: - filter_kwargs = {} - if os_options.get('region_name'): - filter_kwargs['attr'] = 'region' - filter_kwargs['filter_value'] = os_options['region_name'] endpoint = _ksclient.service_catalog.url_for( service_type=service_type, endpoint_type=endpoint_type, @@ -717,9 +755,12 @@ def get_auth(auth_url, user, key, **kwargs): if kwargs.get('tenant_name'): os_options['tenant_name'] = kwargs['tenant_name'] - if not (os_options.get('tenant_name') or os_options.get('tenant_id') or - os_options.get('project_name') or - os_options.get('project_id')): + if os_options.get('auth_type') == 'v3applicationcredential': + pass + elif not (os_options.get('tenant_name') or + os_options.get('tenant_id') or + os_options.get('project_name') or + os_options.get('project_id')): if auth_version in AUTH_VERSIONS_V2: raise ClientException('No tenant specified') raise ClientException('No project name or project id specified.') diff --git a/swiftclient/service.py b/swiftclient/service.py index fb334fd..b89399f 100644 --- a/swiftclient/service.py +++ b/swiftclient/service.py @@ -110,6 +110,9 @@ def process_options(options): else: options['auth_version'] = '2.0' + if options.get('os_auth_type', None) == 'v3applicationcredential': + options['auth_version'] == '3' + # Use new-style args if old ones not present if not options['auth'] and options['os_auth_url']: options['auth'] = options['os_auth_url'] @@ -134,6 +137,11 @@ def process_options(options): 'auth_token': options['os_auth_token'], 'object_storage_url': options['os_storage_url'], 'region_name': options['os_region_name'], + 'auth_type': options['os_auth_type'], + 'application_credential_id': + options['os_application_credential_id'], + 'application_credential_secret': + options['os_application_credential_secret'], } @@ -162,6 +170,11 @@ def _build_default_global_options(): "os_project_domain_id": environ.get('OS_PROJECT_DOMAIN_ID'), "os_auth_url": environ.get('OS_AUTH_URL'), "os_auth_token": environ.get('OS_AUTH_TOKEN'), + "os_auth_type": environ.get('OS_AUTH_TYPE'), + "os_application_credential_id": + environ.get('OS_APPLICATION_CREDENTIAL_ID'), + "os_application_credential_secret": + environ.get('OS_APPLICATION_CREDENTIAL_SECRET'), "os_storage_url": environ.get('OS_STORAGE_URL'), "os_region_name": environ.get('OS_REGION_NAME'), "os_service_type": environ.get('OS_SERVICE_TYPE'), diff --git a/swiftclient/shell.py b/swiftclient/shell.py index 1b34c08..0fef755 100755 --- a/swiftclient/shell.py +++ b/swiftclient/shell.py @@ -1651,16 +1651,27 @@ def parse_args(parser, args, enforce_requires=True): return options, args if enforce_requires: - if options['auth_version'] == '3': + if options['os_auth_type'] == 'v3applicationcredential': + if not (options['os_application_credential_id'] and + options['os_application_credential_secret']): + exit('Auth version 3 (application credential) requires ' + 'OS_APPLICATION_CREDENTIAL_ID and ' + 'OS_APPLICATION_CREDENTIAL_SECRET to be set or ' + 'overridden with --os-application-credential-id and ' + '--os-application-credential-secret respectively.') + elif options['os_auth_type']: + exit('Only "v3applicationcredential" is supported for ' + '--os-auth-type') + elif options['auth_version'] == '3': if not options['auth']: - exit('Auth version 3 requires OS_AUTH_URL to be set or ' + + exit('Auth version 3 requires OS_AUTH_URL to be set or ' 'overridden with --os-auth-url') if not (options['user'] or options['os_user_id']): - exit('Auth version 3 requires either OS_USERNAME or ' + - 'OS_USER_ID to be set or overridden with ' + + exit('Auth version 3 requires either OS_USERNAME or ' + 'OS_USER_ID to be set or overridden with ' '--os-username or --os-user-id respectively.') if not options['key']: - exit('Auth version 3 requires OS_PASSWORD to be set or ' + + exit('Auth version 3 requires OS_PASSWORD to be set or ' 'overridden with --os-password') elif not (options['auth'] and options['user'] and options['key']): exit(''' @@ -1831,6 +1842,29 @@ def add_default_args(parser): 'env[OS_AUTH_URL].') os_grp.add_argument('--os_auth_url', help=argparse.SUPPRESS) + os_grp.add_argument('--os-auth-type', + metavar='<auth-type>', + default=environ.get('OS_AUTH_TYPE'), + help='OpenStack auth type for v3. Defaults to ' + 'env[OS_AUTH_TYPE].') + os_grp.add_argument('--os_auth_type', + help=argparse.SUPPRESS) + os_grp.add_argument('--os-application-credential-id', + metavar='<auth-application-credential-id>', + default=environ.get('OS_APPLICATION_CREDENTIAL_ID'), + help='OpenStack appplication credential id. ' + 'Defaults to env[OS_APPLICATION_CREDENTIAL_ID].') + os_grp.add_argument('--os_application_credential_id', + help=argparse.SUPPRESS) + os_grp.add_argument('--os-application-credential-secret', + metavar='<auth-application-credential-secret>', + default=environ.get( + 'OS_APPLICATION_CREDENTIAL_SECRET'), + help='OpenStack appplication credential secret. ' + 'Defaults to ' + 'env[OS_APPLICATION_CREDENTIAL_SECRET].') + os_grp.add_argument('--os_application_credential_secret', + help=argparse.SUPPRESS) os_grp.add_argument('--os-auth-token', metavar='<auth-token>', default=environ.get('OS_AUTH_TOKEN'), @@ -1915,6 +1949,11 @@ def main(arguments=None): [--os-project-domain-name <auth-project-domain-name>] [--os-auth-url <auth-url>] [--os-auth-token <auth-token>] + [--os-auth-type <os-auth-type>] + [--os-application-credential-id + <auth-application-credential-id>] + [--os-application-credential-secret + <auth-application-credential-secret>] [--os-storage-url <storage-url>] [--os-region-name <region-name>] [--os-service-type <service-type>] @@ -1967,6 +2006,11 @@ Examples: --os-user-id abcdef0123456789abcdef0123456789 \\ --os-password password list + %(prog)s --os-auth-url https://api.example.com/v3 --auth-version 3\\ + --os-application-credential-id d78683c92f0e4f9b9b02a2e208039412 \\ + --os-application-credential-secret APPLICTION_CREDENTIAL_SECRET \\ + --os-auth-type v3applicationcredential list + %(prog)s --os-auth-token 6ee5eb33efad4e45ab46806eac010566 \\ --os-storage-url https://10.1.5.2:8080/v1/AUTH_ced809b6a4baea7aeab61a \\ list |