Support Keystone V3 with HttpClient
The http way doesn't work with keystone v3. This patch update the HttpClient to support it. Closes-bug: #1546280 Change-Id: Iefa1aafb796609aca076ed6ab73d02c92b9198d0
This commit is contained in:
parent
4eb63b8ef2
commit
e1014faed1
@ -205,7 +205,8 @@ class HTTPClient(object):
|
||||
bypass_url=None, retries=None,
|
||||
http_log_debug=False, cacert=None,
|
||||
auth_system='keystone', auth_plugin=None, api_version=None,
|
||||
logger=None):
|
||||
logger=None, user_domain_name='Default',
|
||||
project_domain_name='Default'):
|
||||
self.user = user
|
||||
self.password = password
|
||||
self.projectid = projectid
|
||||
@ -236,6 +237,8 @@ class HTTPClient(object):
|
||||
self.proxy_token = proxy_token
|
||||
self.proxy_tenant_id = proxy_tenant_id
|
||||
self.timeout = timeout
|
||||
self.user_domain_name = user_domain_name
|
||||
self.project_domain_name = project_domain_name
|
||||
|
||||
if insecure:
|
||||
self.verify_cert = False
|
||||
@ -419,8 +422,8 @@ class HTTPClient(object):
|
||||
We may get redirected to another site, fail or actually get
|
||||
back a service catalog with a token and our endpoints.
|
||||
"""
|
||||
|
||||
if resp.status_code == 200: # content must always present
|
||||
# content must always present
|
||||
if resp.status_code == 200 or resp.status_code == 201:
|
||||
try:
|
||||
self.auth_url = url
|
||||
self.auth_ref = access.create(resp=resp, body=body)
|
||||
@ -497,10 +500,10 @@ class HTTPClient(object):
|
||||
path, query, frag))
|
||||
|
||||
auth_url = self.auth_url
|
||||
if self.version == "v2.0":
|
||||
if self.version == "v2.0" or self.version == "v3":
|
||||
while auth_url:
|
||||
if not self.auth_system or self.auth_system == 'keystone':
|
||||
auth_url = self._v2_auth(auth_url)
|
||||
auth_url = self._v2_or_v3_auth(auth_url)
|
||||
else:
|
||||
auth_url = self._plugin_auth(auth_url)
|
||||
|
||||
@ -526,7 +529,7 @@ class HTTPClient(object):
|
||||
except exceptions.AuthorizationFailure:
|
||||
if auth_url.find('v2.0') < 0:
|
||||
auth_url = auth_url + '/v2.0'
|
||||
self._v2_auth(auth_url)
|
||||
self._v2_or_v3_auth(auth_url)
|
||||
|
||||
if self.bypass_url:
|
||||
self.set_management_url(self.bypass_url)
|
||||
@ -559,23 +562,43 @@ class HTTPClient(object):
|
||||
def _plugin_auth(self, auth_url):
|
||||
return self.auth_plugin.authenticate(self, auth_url)
|
||||
|
||||
def _v2_auth(self, url):
|
||||
def _v2_or_v3_auth(self, url):
|
||||
"""Authenticate against a v2.0 auth service."""
|
||||
body = {"auth": {
|
||||
"passwordCredentials": {"username": self.user,
|
||||
"password": self.password}}}
|
||||
if self.version == "v3":
|
||||
body = {
|
||||
"auth": {
|
||||
"identity": {
|
||||
"methods": ["password"],
|
||||
"password": {"user": {
|
||||
"domain": {"name": self.user_domain_name},
|
||||
"name": self.user,
|
||||
"password": self.password}}},
|
||||
}
|
||||
}
|
||||
scope = {"project": {"domain": {"name": self.project_domain_name}}}
|
||||
if self.projectid:
|
||||
scope['project']['name'] = self.projectid
|
||||
elif self.tenant_id:
|
||||
scope['project']['id'] = self.tenant_id
|
||||
|
||||
if self.projectid:
|
||||
body['auth']['tenantName'] = self.projectid
|
||||
elif self.tenant_id:
|
||||
body['auth']['tenantId'] = self.tenant_id
|
||||
body["auth"]["scope"] = scope
|
||||
else:
|
||||
body = {"auth": {
|
||||
"passwordCredentials": {"username": self.user,
|
||||
"password": self.password}}}
|
||||
|
||||
if self.projectid:
|
||||
body['auth']['tenantName'] = self.projectid
|
||||
elif self.tenant_id:
|
||||
body['auth']['tenantId'] = self.tenant_id
|
||||
self._authenticate(url, body)
|
||||
|
||||
def _authenticate(self, url, body):
|
||||
"""Authenticate and extract the service catalog."""
|
||||
token_url = url + "/tokens"
|
||||
|
||||
if self.version == 'v3':
|
||||
token_url = url + "/auth/tokens"
|
||||
else:
|
||||
token_url = url + "/tokens"
|
||||
# Make sure we follow redirects when trying to reach Keystone
|
||||
resp, body = self.request(
|
||||
token_url,
|
||||
|
@ -11,6 +11,7 @@
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
|
||||
import json
|
||||
import mock
|
||||
import requests
|
||||
|
||||
@ -25,6 +26,12 @@ fake_response = utils.TestResponse({
|
||||
})
|
||||
mock_request = mock.Mock(return_value=(fake_response))
|
||||
|
||||
fake_201_response = utils.TestResponse({
|
||||
"status_code": 201,
|
||||
"text": '{"hi": "there"}',
|
||||
})
|
||||
mock_201_request = mock.Mock(return_value=(fake_201_response))
|
||||
|
||||
refused_response = utils.TestResponse({
|
||||
"status_code": 400,
|
||||
"text": '[Errno 111] Connection refused',
|
||||
@ -293,6 +300,47 @@ class ClientTest(utils.TestCase):
|
||||
|
||||
test_auth_call()
|
||||
|
||||
def test_auth_with_keystone_v3(self):
|
||||
cl = get_authed_client()
|
||||
cl.auth_url = 'http://example.com:5000/v3'
|
||||
|
||||
@mock.patch.object(cl, "_extract_service_catalog", mock.Mock())
|
||||
@mock.patch.object(requests, "request", mock_201_request)
|
||||
def test_auth_call():
|
||||
cl.authenticate()
|
||||
headers = {
|
||||
"Content-Type": "application/json",
|
||||
'Accept': 'application/json',
|
||||
"User-Agent": cl.USER_AGENT
|
||||
}
|
||||
data = {
|
||||
"auth": {
|
||||
"scope": {
|
||||
"project": {
|
||||
"domain": {"name": "Default"},
|
||||
"name": "project_id"
|
||||
}
|
||||
},
|
||||
"identity": {
|
||||
"methods": ["password"],
|
||||
"password": {
|
||||
"user": {"domain": {"name": "Default"},
|
||||
"password": "password", "name": "username"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
mock_201_request.assert_called_with(
|
||||
"POST",
|
||||
"http://example.com:5000/v3/auth/tokens",
|
||||
headers=headers,
|
||||
allow_redirects=True,
|
||||
data=json.dumps(data),
|
||||
**self.TEST_REQUEST_BASE)
|
||||
|
||||
test_auth_call()
|
||||
|
||||
def test_get_retry_timeout_error(self):
|
||||
cl = get_authed_client(retries=1)
|
||||
|
||||
|
@ -0,0 +1,4 @@
|
||||
---
|
||||
features:
|
||||
- |
|
||||
Support Keystone V3 authentication for httpClient.
|
Loading…
Reference in New Issue
Block a user