diff --git a/neutronclient/client.py b/neutronclient/client.py index c79cd0beb..cd71e1b4f 100644 --- a/neutronclient/client.py +++ b/neutronclient/client.py @@ -94,7 +94,8 @@ class HTTPClient(object): USER_AGENT = 'python-neutronclient' - def __init__(self, username=None, tenant_name=None, tenant_id=None, + def __init__(self, username=None, user_id=None, + tenant_name=None, tenant_id=None, password=None, auth_url=None, token=None, region_name=None, timeout=None, endpoint_url=None, insecure=False, @@ -104,6 +105,7 @@ class HTTPClient(object): **kwargs): self.username = username + self.user_id = user_id self.tenant_name = tenant_name self.tenant_id = tenant_id self.password = password @@ -232,15 +234,18 @@ class HTTPClient(object): endpoint_type=self.endpoint_type) def _authenticate_keystone(self): + if self.user_id: + creds = {'userId': self.user_id, + 'password': self.password} + else: + creds = {'username': self.username, + 'password': self.password} + if self.tenant_id: - body = {'auth': {'passwordCredentials': - {'username': self.username, - 'password': self.password, }, + body = {'auth': {'passwordCredentials': creds, 'tenantId': self.tenant_id, }, } else: - body = {'auth': {'passwordCredentials': - {'username': self.username, - 'password': self.password, }, + body = {'auth': {'passwordCredentials': creds, 'tenantName': self.tenant_name, }, } if self.auth_url is None: diff --git a/neutronclient/common/clientmanager.py b/neutronclient/common/clientmanager.py index b36d21e5a..db6883b86 100644 --- a/neutronclient/common/clientmanager.py +++ b/neutronclient/common/clientmanager.py @@ -52,8 +52,11 @@ class ClientManager(object): def __init__(self, token=None, url=None, auth_url=None, endpoint_type=None, - tenant_name=None, tenant_id=None, - username=None, password=None, + tenant_name=None, + tenant_id=None, + username=None, + user_id=None, + password=None, region_name=None, api_version=None, auth_strategy=None, @@ -70,6 +73,7 @@ class ClientManager(object): self._tenant_name = tenant_name self._tenant_id = tenant_id self._username = username + self._user_id = user_id self._password = password self._region_name = region_name self._api_version = api_version @@ -84,6 +88,7 @@ class ClientManager(object): if not self._url: httpclient = client.HTTPClient( username=self._username, + user_id=self._user_id, tenant_name=self._tenant_name, tenant_id=self._tenant_id, password=self._password, diff --git a/neutronclient/shell.py b/neutronclient/shell.py index 05e91ac52..c1cba5c5b 100644 --- a/neutronclient/shell.py +++ b/neutronclient/shell.py @@ -398,7 +398,7 @@ class NeutronShell(app.App): parser.add_argument( '--os-tenant-id', metavar='', default=env('OS_TENANT_ID'), - help=_('Authentication tenant name (Env: OS_TENANT_ID)')) + help=_('Authentication tenant ID (Env: OS_TENANT_ID)')) parser.add_argument( '--os-username', metavar='', @@ -408,6 +408,11 @@ class NeutronShell(app.App): '--os_username', help=argparse.SUPPRESS) + parser.add_argument( + '--os-user-id', metavar='', + default=env('OS_USER_ID'), + help=_('Authentication user ID (Env: OS_USER_ID)')) + parser.add_argument( '--os-password', metavar='', default=utils.env('OS_PASSWORD'), @@ -590,10 +595,12 @@ class NeutronShell(app.App): else: # Validate password flow auth - if not self.options.os_username: + if (not self.options.os_username + and not self.options.os_user_id): raise exc.CommandError( - _("You must provide a username via" - " either --os-username or env[OS_USERNAME]")) + _("You must provide a username or user ID via" + " --os-username, env[OS_USERNAME] or" + " --os-user_id, env[OS_USER_ID]")) if not self.options.os_password: raise exc.CommandError( @@ -624,6 +631,7 @@ class NeutronShell(app.App): tenant_name=self.options.os_tenant_name, tenant_id=self.options.os_tenant_id, username=self.options.os_username, + user_id=self.options.os_user_id, password=self.options.os_password, region_name=self.options.os_region_name, api_version=self.api_version, diff --git a/neutronclient/tests/unit/test_auth.py b/neutronclient/tests/unit/test_auth.py index 485d51132..585458e15 100644 --- a/neutronclient/tests/unit/test_auth.py +++ b/neutronclient/tests/unit/test_auth.py @@ -28,8 +28,9 @@ from neutronclient.common import utils USERNAME = 'testuser' +USER_ID = 'testuser_id' TENANT_NAME = 'testtenant' -TENANT_ID = 'testtenantid' +TENANT_ID = 'testtenant_id' PASSWORD = 'password' AUTH_URL = 'authurl' ENDPOINT_URL = 'localurl' @@ -107,8 +108,10 @@ class CLITestAuthNoAuth(testtools.TestCase): class CLITestAuthKeystone(testtools.TestCase): - # Auth Body expected when using tenant name - auth_type = 'tenantName' + # Auth Body expected + auth_body = ('{"auth": {"tenantName": "testtenant", ' + '"passwordCredentials": ' + '{"username": "testuser", "password": "password"}}}') def setUp(self): """Prepare the test environment.""" @@ -127,7 +130,6 @@ class CLITestAuthKeystone(testtools.TestCase): instantiated with predefined token. """ client_ = client.HTTPClient(username=USERNAME, - tenant_id=TENANT_ID, tenant_name=TENANT_NAME, token=TOKEN, password=PASSWORD, @@ -146,7 +148,7 @@ class CLITestAuthKeystone(testtools.TestCase): self.client.request( AUTH_URL + '/tokens', 'POST', - body=mox.StrContains(self.auth_type), headers=mox.IsA(dict) + body=self.auth_body, headers=mox.IsA(dict) ).AndReturn((res200, json.dumps(KS_TOKEN_RESULT))) self.client.request( mox.StrContains(ENDPOINT_URL + '/resource'), 'GET', @@ -447,13 +449,15 @@ class CLITestAuthKeystone(testtools.TestCase): class CLITestAuthKeystoneWithId(CLITestAuthKeystone): - # Auth Body expected when using tenant Id - auth_type = 'tenantId' + # Auth Body expected + auth_body = ('{"auth": {"passwordCredentials": ' + '{"password": "password", "userId": "testuser_id"}, ' + '"tenantId": "testtenant_id"}}') def setUp(self): """Prepare the test environment.""" super(CLITestAuthKeystoneWithId, self).setUp() - self.client = client.HTTPClient(username=USERNAME, + self.client = client.HTTPClient(user_id=USER_ID, tenant_id=TENANT_ID, password=PASSWORD, auth_url=AUTH_URL, @@ -462,13 +466,16 @@ class CLITestAuthKeystoneWithId(CLITestAuthKeystone): class CLITestAuthKeystoneWithIdandName(CLITestAuthKeystone): - # Auth Body expected when using tenant Id - auth_type = 'tenantId' + # Auth Body expected + auth_body = ('{"auth": {"passwordCredentials": ' + '{"password": "password", "userId": "testuser_id"}, ' + '"tenantId": "testtenant_id"}}') def setUp(self): """Prepare the test environment.""" super(CLITestAuthKeystoneWithIdandName, self).setUp() self.client = client.HTTPClient(username=USERNAME, + user_id=USER_ID, tenant_id=TENANT_ID, tenant_name=TENANT_NAME, password=PASSWORD, diff --git a/neutronclient/tests/unit/test_shell.py b/neutronclient/tests/unit/test_shell.py index e5fe54252..9c50fe938 100644 --- a/neutronclient/tests/unit/test_shell.py +++ b/neutronclient/tests/unit/test_shell.py @@ -117,13 +117,15 @@ class ShellTest(testtools.TestCase): 'either --os-url or env[OS_URL]', stderr.strip()) def test_auth(self): + #import pdb; pdb.set_trace() neutron_shell = openstack_shell.NeutronShell('2.0') self.addCleanup(self.mox.UnsetStubs) self.mox.StubOutWithMock(clientmanager.ClientManager, '__init__') self.mox.StubOutWithMock(neutron_shell, 'run_subcommand') clientmanager.ClientManager.__init__( token='', url='', auth_url='http://127.0.0.1:5000/', - tenant_name='test', tenant_id='tenant_id', username='test', + tenant_name='test', tenant_id='tenant_id', + username='test', user_id='', password='test', region_name='', api_version={'network': '2.0'}, auth_strategy='keystone', service_type='network', endpoint_type='publicURL', insecure=False, ca_cert=None, diff --git a/neutronclient/tests/unit/test_ssl.py b/neutronclient/tests/unit/test_ssl.py index 81f831ba7..91d052589 100644 --- a/neutronclient/tests/unit/test_ssl.py +++ b/neutronclient/tests/unit/test_ssl.py @@ -61,6 +61,7 @@ class TestSSL(testtools.TestCase): token=mox.IgnoreArg(), url=mox.IgnoreArg(), username=mox.IgnoreArg(), + user_id=mox.IgnoreArg(), log_credentials=mox.IgnoreArg(), ) openstack_shell.NeutronShell.interact().AndReturn(0) @@ -91,6 +92,7 @@ class TestSSL(testtools.TestCase): token=mox.IgnoreArg(), url=mox.IgnoreArg(), username=mox.IgnoreArg(), + user_id=mox.IgnoreArg(), log_credentials=mox.IgnoreArg(), ) openstack_shell.NeutronShell.interact().AndReturn(0) diff --git a/neutronclient/v2_0/client.py b/neutronclient/v2_0/client.py index cf1a214f6..7b6b1ce3e 100644 --- a/neutronclient/v2_0/client.py +++ b/neutronclient/v2_0/client.py @@ -108,6 +108,7 @@ class Client(object): """Client for the OpenStack Neutron v2.0 API. :param string username: Username for authentication. (optional) + :param string user_id: User ID for authentication. (optional) :param string password: Password for authentication. (optional) :param string token: Token for authentication. (optional) :param string tenant_name: Tenant name. (optional)