From b7263eab1da5ac016de83a28ed9cf5a754b85b6d Mon Sep 17 00:00:00 2001 From: Anton Nikulin Date: Thu, 13 Sep 2018 17:04:30 +0300 Subject: [PATCH] Store Authorization header inside HttpApi connection plugin (#45598) --- lib/ansible/plugins/httpapi/ftd.py | 20 +++++--------------- test/units/plugins/httpapi/test_ftd.py | 23 ++++++++++++----------- 2 files changed, 17 insertions(+), 26 deletions(-) diff --git a/lib/ansible/plugins/httpapi/ftd.py b/lib/ansible/plugins/httpapi/ftd.py index 2b1f45c5f2a..33366232ef9 100644 --- a/lib/ansible/plugins/httpapi/ftd.py +++ b/lib/ansible/plugins/httpapi/ftd.py @@ -109,6 +109,7 @@ class HttpApi(HttpApiBase): try: self.refresh_token = response['refresh_token'] self.access_token = response['access_token'] + self.connection._auth = {'Authorization': 'Bearer %s' % self.access_token} except KeyError: raise ConnectionError( 'Server returned response without token info during connection authentication: %s' % response) @@ -121,7 +122,7 @@ class HttpApi(HttpApiBase): } self.connection.send( self._get_api_token_path(), json.dumps(auth_payload), method=HTTPMethod.POST, - headers=self._authorized_headers() + headers=BASE_HEADERS ) self.refresh_token = None self.access_token = None @@ -134,10 +135,7 @@ class HttpApi(HttpApiBase): url = construct_url_path(url_path, path_params, query_params) data = json.dumps(body_params) if body_params else None try: - response, response_data = self.connection.send( - url, data, method=http_method, - headers=self._authorized_headers() - ) + response, response_data = self.connection.send(url, data, method=http_method, headers=BASE_HEADERS) return { ResponseParams.SUCCESS: True, ResponseParams.STATUS_CODE: response.getcode(), @@ -159,7 +157,7 @@ class HttpApi(HttpApiBase): rf.make_multipart() body, content_type = encode_multipart_formdata([rf]) - headers = self._authorized_headers() + headers = dict(BASE_HEADERS) headers['Content-Type'] = content_type headers['Content-Length'] = len(body) @@ -168,10 +166,7 @@ class HttpApi(HttpApiBase): def download_file(self, from_url, to_path, path_params=None): url = construct_url_path(from_url, path_params=path_params) - response, response_data = self.connection.send( - url, data=None, method=HTTPMethod.GET, - headers=self._authorized_headers() - ) + response, response_data = self.connection.send(url, data=None, method=HTTPMethod.GET, headers=BASE_HEADERS) if os.path.isdir(to_path): filename = extract_filename_from_headers(response.info()) @@ -188,11 +183,6 @@ class HttpApi(HttpApiBase): # None means that the exception will be passed further to the caller return None - def _authorized_headers(self): - headers = dict(BASE_HEADERS) - headers['Authorization'] = 'Bearer %s' % self.access_token - return headers - def _get_api_spec_path(self): return self.get_option('spec_path') diff --git a/test/units/plugins/httpapi/test_ftd.py b/test/units/plugins/httpapi/test_ftd.py index 3a5dd0a4e87..f382e3e949d 100644 --- a/test/units/plugins/httpapi/test_ftd.py +++ b/test/units/plugins/httpapi/test_ftd.py @@ -37,6 +37,11 @@ if PY3: else: BUILTINS_NAME = '__builtin__' +EXPECTED_BASE_HEADERS = { + 'Accept': 'application/json', + 'Content-Type': 'application/json' +} + class FakeFtdHttpApiPlugin(HttpApi): def __init__(self, conn): @@ -67,6 +72,7 @@ class TestFtdHttpApi(unittest.TestCase): assert 'ACCESS_TOKEN' == self.ftd_plugin.access_token assert 'REFRESH_TOKEN' == self.ftd_plugin.refresh_token + assert {'Authorization': 'Bearer ACCESS_TOKEN'} == self.ftd_plugin.connection._auth expected_body = json.dumps({'grant_type': 'password', 'username': 'foo', 'password': 'bar'}) self.connection_mock.send.assert_called_once_with(mock.ANY, expected_body, headers=mock.ANY, method=mock.ANY) @@ -80,6 +86,7 @@ class TestFtdHttpApi(unittest.TestCase): assert 'NEW_ACCESS_TOKEN' == self.ftd_plugin.access_token assert 'NEW_REFRESH_TOKEN' == self.ftd_plugin.refresh_token + assert {'Authorization': 'Bearer NEW_ACCESS_TOKEN'} == self.ftd_plugin.connection._auth expected_body = json.dumps({'grant_type': 'refresh_token', 'refresh_token': 'REFRESH_TOKEN'}) self.connection_mock.send.assert_called_once_with(mock.ANY, expected_body, headers=mock.ANY, method=mock.ANY) @@ -92,7 +99,8 @@ class TestFtdHttpApi(unittest.TestCase): self.ftd_plugin.login('foo', 'bar') - self.connection_mock.send.assert_called_once_with('/testFakeLoginUrl', mock.ANY, headers=mock.ANY, method=mock.ANY) + self.connection_mock.send.assert_called_once_with('/testFakeLoginUrl', mock.ANY, headers=mock.ANY, + method=mock.ANY) self.ftd_plugin.hostvars['token_path'] = temp_token_path def test_login_raises_exception_when_no_refresh_token_and_no_credentials(self): @@ -135,7 +143,7 @@ class TestFtdHttpApi(unittest.TestCase): assert {ResponseParams.SUCCESS: True, ResponseParams.STATUS_CODE: 200, ResponseParams.RESPONSE: exp_resp} == resp self.connection_mock.send.assert_called_once_with('/test/123?at=0', '{"name": "foo"}', method=HTTPMethod.PUT, - headers=self._expected_headers()) + headers=EXPECTED_BASE_HEADERS) def test_send_request_should_return_empty_dict_when_no_response_data(self): self.connection_mock.send.return_value = self._connection_response(None) @@ -144,7 +152,7 @@ class TestFtdHttpApi(unittest.TestCase): assert {ResponseParams.SUCCESS: True, ResponseParams.STATUS_CODE: 200, ResponseParams.RESPONSE: {}} == resp self.connection_mock.send.assert_called_once_with('/test', None, method=HTTPMethod.GET, - headers=self._expected_headers()) + headers=EXPECTED_BASE_HEADERS) def test_send_request_should_return_error_info_when_http_error_raises(self): self.connection_mock.send.side_effect = HTTPError('http://testhost.com', 500, '', {}, @@ -215,7 +223,7 @@ class TestFtdHttpApi(unittest.TestCase): resp = self.ftd_plugin.upload_file('/tmp/test.txt', '/files') assert {'id': '123'} == resp - exp_headers = self._expected_headers() + exp_headers = dict(EXPECTED_BASE_HEADERS) exp_headers['Content-Length'] = len('--Encoded data--') exp_headers['Content-Type'] = 'multipart/form-data' self.connection_mock.send.assert_called_once_with('/files', data='--Encoded data--', @@ -262,10 +270,3 @@ class TestFtdHttpApi(unittest.TestCase): response_text = json.dumps(response) if type(response) is dict else response response_data = BytesIO(response_text.encode() if response_text else ''.encode()) return response_mock, response_data - - def _expected_headers(self): - return { - 'Accept': 'application/json', - 'Authorization': 'Bearer %s' % self.ftd_plugin.access_token, - 'Content-Type': 'application/json' - }