summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--heatclient/common/http.py13
-rw-r--r--heatclient/shell.py11
-rw-r--r--heatclient/tests/test_common_http.py75
3 files changed, 96 insertions, 3 deletions
diff --git a/heatclient/common/http.py b/heatclient/common/http.py
index 66ab996..6e801bd 100644
--- a/heatclient/common/http.py
+++ b/heatclient/common/http.py
@@ -53,6 +53,7 @@ class HTTPClient(object):
self.username = kwargs.get('username')
self.password = kwargs.get('password')
self.region_name = kwargs.get('region_name')
+ self.include_pass = kwargs.get('include_pass')
self.connection_params = self.get_connection_params(endpoint, **kwargs)
@staticmethod
@@ -137,6 +138,8 @@ class HTTPClient(object):
kwargs['headers'].setdefault('X-Auth-Url', self.auth_url)
if self.region_name:
kwargs['headers'].setdefault('X-Region-Name', self.region_name)
+ if self.include_pass and not 'X-Auth-Key' in kwargs['headers']:
+ kwargs['headers'].update(self.credentials_headers())
self.log_curl_request(method, url, kwargs)
conn = self.get_connection()
@@ -160,7 +163,15 @@ class HTTPClient(object):
body_str = ''.join([chunk for chunk in body_iter])
self.log_http_response(resp, body_str)
- if 400 <= resp.status < 600:
+ if not 'X-Auth-Key' in kwargs['headers'] and \
+ (resp.status == 401 or
+ (resp.status == 500 and "(HTTP 401)" in body_str)):
+ raise exc.HTTPUnauthorized("Authentication failed. Please try"
+ " again with option "
+ "--include-password or export "
+ "HEAT_INCLUDE_PASSWORD=1\n%s"
+ % body_str)
+ elif 400 <= resp.status < 600:
raise exc.from_response(resp, body_str)
elif resp.status in (301, 302, 305):
# Redirected. Reissue the request to the new location.
diff --git a/heatclient/shell.py b/heatclient/shell.py
index 434fc9e..d04a9d1 100644
--- a/heatclient/shell.py
+++ b/heatclient/shell.py
@@ -176,6 +176,11 @@ class HeatShell(object):
parser.add_argument('--os_endpoint_type',
help=argparse.SUPPRESS)
+ parser.add_argument('--include-password',
+ default=bool(utils.env('HEAT_INCLUDE_PASSWORD')),
+ action='store_true',
+ help='Send os-username and os-password to heat')
+
return parser
def get_subcommand_parser(self, version):
@@ -328,7 +333,8 @@ class HeatShell(object):
'auth_url': args.os_auth_url,
'service_type': args.os_service_type,
'endpoint_type': args.os_endpoint_type,
- 'insecure': args.insecure
+ 'insecure': args.insecure,
+ 'include_pass': args.include_password
}
endpoint = args.heat_url
@@ -346,7 +352,8 @@ class HeatShell(object):
'key_file': args.key_file,
'username': args.os_username,
'password': args.os_password,
- 'endpoint_type': args.os_endpoint_type
+ 'endpoint_type': args.os_endpoint_type,
+ 'include_pass': args.include_password
}
if args.os_region_name:
diff --git a/heatclient/tests/test_common_http.py b/heatclient/tests/test_common_http.py
index 9398347..9a8a157 100644
--- a/heatclient/tests/test_common_http.py
+++ b/heatclient/tests/test_common_http.py
@@ -100,6 +100,81 @@ class HttpClientTest(testtools.TestCase):
self.assertEqual(resp.status, 200)
self.m.VerifyAll()
+ def test_include_pass(self):
+ # Record a 200
+ fake200 = fakes.FakeHTTPResponse(
+ 200, 'OK',
+ {'content-type': 'application/octet-stream'},
+ '')
+
+ # no token or credentials
+ mock_conn = http.httplib.HTTPConnection('example.com', 8004,
+ timeout=600.0)
+ mock_conn.request('GET', '/',
+ headers={'Content-Type': 'application/octet-stream',
+ 'User-Agent': 'python-heatclient'})
+ mock_conn.getresponse().AndReturn(fake200)
+
+ # credentials
+ mock_conn = http.httplib.HTTPConnection('example.com', 8004,
+ timeout=600.0)
+ mock_conn.request('GET', '/',
+ headers={'Content-Type': 'application/octet-stream',
+ 'User-Agent': 'python-heatclient',
+ 'X-Auth-Key': 'pass',
+ 'X-Auth-User': 'user'})
+ mock_conn.getresponse().AndReturn(fake200)
+
+ # token suppresses credentials
+ mock_conn = http.httplib.HTTPConnection('example.com', 8004,
+ timeout=600.0)
+ mock_conn.request('GET', '/',
+ headers={'Content-Type': 'application/octet-stream',
+ 'User-Agent': 'python-heatclient',
+ 'X-Auth-Token': 'abcd1234',
+ 'X-Auth-Key': 'pass',
+ 'X-Auth-User': 'user'})
+ mock_conn.getresponse().AndReturn(fake200)
+
+ # Replay, create client, assert
+ self.m.ReplayAll()
+ client = http.HTTPClient('http://example.com:8004')
+ resp, body = client.raw_request('GET', '')
+ self.assertEqual(200, resp.status)
+
+ client.username = 'user'
+ client.password = 'pass'
+ client.include_pass = True
+ resp, body = client.raw_request('GET', '')
+ self.assertEqual(200, resp.status)
+
+ client.auth_token = 'abcd1234'
+ resp, body = client.raw_request('GET', '')
+ self.assertEqual(200, resp.status)
+ self.m.VerifyAll()
+
+ def test_not_include_pass(self):
+ # Record a 200
+ fake500 = fakes.FakeHTTPResponse(
+ 500, 'ERROR',
+ {'content-type': 'application/octet-stream'},
+ '(HTTP 401)')
+
+ # no token or credentials
+ mock_conn = http.httplib.HTTPConnection('example.com', 8004,
+ timeout=600.0)
+ mock_conn.request('GET', '/',
+ headers={'Content-Type': 'application/octet-stream',
+ 'User-Agent': 'python-heatclient'})
+ mock_conn.getresponse().AndReturn(fake500)
+
+ # Replay, create client, assert
+ self.m.ReplayAll()
+ client = http.HTTPClient('http://example.com:8004')
+ e = self.assertRaises(exc.HTTPUnauthorized,
+ client.raw_request, 'GET', '')
+ self.assertIn('include-password', str(e))
+
def test_region_name(self):
# Record a 200
fake200 = fakes.FakeHTTPResponse(