Refactoring GET request handling. (#45051)

(cherry picked from commit 26edeb7cce)
pull/48175/head
Felix Fontein 6 years ago committed by Matt Clay
parent af00a9da8d
commit 83e2fa7473

@ -60,27 +60,12 @@ def nopad_b64(data):
return base64.urlsafe_b64encode(data).decode('utf8').replace("=", "")
def simple_get(module, url):
resp, info = fetch_url(module, url, method='GET')
result = {}
def read_file(fn, mode='b'):
try:
content = resp.read()
except AttributeError:
content = info.get('body')
if content:
if info['content-type'].startswith('application/json'):
try:
result = module.from_json(content.decode('utf8'))
except ValueError:
raise ModuleFailException("Failed to parse the ACME response: {0} {1}".format(url, content))
else:
result = content
if info['status'] >= 400:
raise ModuleFailException("ACME request failed: CODE: {0} RESULT: {1}".format(info['status'], result))
return result
with open(fn, 'r' + mode) as f:
return f.read()
except Exception as e:
raise ModuleFailException('Error while reading file "{0}": {1}'.format(fn, e))
# function source: network/basics/uri.py
@ -150,12 +135,12 @@ class ACMEDirectory(object):
https://tools.ietf.org/html/draft-ietf-acme-acme-09#section-7.1.1
'''
def __init__(self, module):
def __init__(self, module, account):
self.module = module
self.directory_root = module.params['acme_directory']
self.version = module.params['acme_version']
self.directory = simple_get(self.module, self.directory_root)
self.directory, dummy = account.get_request(self.directory_root)
# Check whether self.version matches what we expect
if self.version == 1:
@ -193,7 +178,6 @@ class ACMEAccount(object):
# account_key path and content are mutually exclusive
self.key = module.params['account_key_src']
self.key_content = module.params['account_key_content']
self.directory = ACMEDirectory(module)
self.uri = None
@ -224,6 +208,8 @@ class ACMEAccount(object):
"jwk": self.jwk,
}
self.directory = ACMEDirectory(module, self)
def get_keyauthorization(self, token):
'''
Returns the key authorization for the given token
@ -355,7 +341,7 @@ class ACMEAccount(object):
"signature": nopad_b64(to_bytes(out)),
}
def send_signed_request(self, url, payload):
def send_signed_request(self, url, payload, parse_json_result=True):
'''
Sends a JWS signed HTTP POST request to the ACME server and returns
the response as dictionary
@ -383,17 +369,19 @@ class ACMEAccount(object):
except AttributeError:
content = info.get('body')
if content:
if info['content-type'].startswith('application/json') or 400 <= info['status'] < 600:
if content or not parse_json_result:
if (parse_json_result and info['content-type'].startswith('application/json')) or 400 <= info['status'] < 600:
try:
result = self.module.from_json(content.decode('utf8'))
decoded_result = self.module.from_json(content.decode('utf8'))
# In case of badNonce error, try again (up to 5 times)
# (https://tools.ietf.org/html/draft-ietf-acme-acme-09#section-6.6)
if (400 <= info['status'] < 600 and
result.get('type') == 'urn:ietf:params:acme:error:badNonce' and
decoded_result.get('type') == 'urn:ietf:params:acme:error:badNonce' and
failed_tries <= 5):
failed_tries += 1
continue
if parse_json_result:
result = decoded_result
except ValueError:
raise ModuleFailException("Failed to parse the ACME response: {0} {1}".format(url, content))
else:
@ -401,6 +389,31 @@ class ACMEAccount(object):
return result, info
def get_request(self, uri, parse_json_result=True, headers=None):
resp, info = fetch_url(self.module, uri, method='GET', headers=headers)
try:
content = resp.read()
except AttributeError:
content = info.get('body')
if parse_json_result:
result = {}
if content:
if info['content-type'].startswith('application/json'):
try:
result = self.module.from_json(content.decode('utf8'))
except ValueError:
raise ModuleFailException("Failed to parse the ACME response: {0} {1}".format(uri, content))
else:
result = content
else:
result = content
if info['status'] >= 400:
raise ModuleFailException("ACME request failed: CODE: {0} RESULT: {1}".format(info['status'], result))
return result, info
def set_account_uri(self, uri):
'''
Set account URI. For ACME v2, it needs to be used to sending signed

@ -303,7 +303,7 @@ account_uri:
'''
from ansible.module_utils.acme import (
ModuleFailException, fetch_url, write_file, nopad_b64, simple_get, ACMEAccount
ModuleFailException, write_file, nopad_b64, ACMEAccount,
)
import base64
@ -515,7 +515,7 @@ class ACMEClient(object):
status = ''
while status not in ['valid', 'invalid', 'revoked']:
result = simple_get(self.module, auth['uri'])
result, dummy = self.account.get_request(auth['uri'])
result['uri'] = auth['uri']
if self._add_or_update_auth(domain, result):
self.changed = True
@ -554,7 +554,7 @@ class ACMEClient(object):
status = result['status']
while status not in ['valid', 'invalid']:
time.sleep(2)
result = simple_get(self.module, order)
result, dummy = self.account.get_request(order)
status = result['status']
if status != 'valid':
@ -575,11 +575,7 @@ class ACMEClient(object):
Download and parse the certificate chain.
https://tools.ietf.org/html/draft-ietf-acme-acme-09#section-7.4.2
'''
resp, info = fetch_url(self.module, url, headers={'Accept': 'application/pem-certificate-chain'})
try:
content = resp.read()
except AttributeError:
content = info.get('body')
content, info = self.account.get_request(url, parse_json_result=False, headers={'Accept': 'application/pem-certificate-chain'})
if not content or not info['content-type'].startswith('application/pem-certificate-chain'):
raise ModuleFailException("Cannot download certificate chain from {0}: {1} (headers: {2})".format(url, content, info))
@ -606,9 +602,9 @@ class ACMEClient(object):
parsed_link = re.match(r'<(.+)>;rel="(\w+)"', link)
if parsed_link and parsed_link.group(2) == "up":
chain_link = parsed_link.group(1)
chain_result, chain_info = fetch_url(self.module, chain_link, method='GET')
chain_result, chain_info = self.account.get_request(chain_link, parse_json_result=False)
if chain_info['status'] in [200, 201]:
chain.append(self._der_to_pem(chain_result.read()))
chain.append(self._der_to_pem(chain_result))
if cert is None or current:
raise ModuleFailException("Failed to parse certificate chain download from {0}: {1} (headers: {2})".format(url, content, info))
@ -635,9 +631,9 @@ class ACMEClient(object):
parsed_link = re.match(r'<(.+)>;rel="(\w+)"', link)
if parsed_link and parsed_link.group(2) == "up":
chain_link = parsed_link.group(1)
chain_result, chain_info = fetch_url(self.module, chain_link, method='GET')
chain_result, chain_info = self.account.get_request(chain_link, parse_json_result=False)
if chain_info['status'] in [200, 201]:
chain = [self._der_to_pem(chain_result.read())]
chain = [self._der_to_pem(chain_result)]
if info['status'] not in [200, 201]:
raise ModuleFailException("Error new cert: CODE: {0} RESULT: {1}".format(info['status'], result))
@ -664,7 +660,7 @@ class ACMEClient(object):
raise ModuleFailException("Error new order: CODE: {0} RESULT: {1}".format(info['status'], result))
for auth_uri in result['authorizations']:
auth_data = simple_get(self.module, auth_uri)
auth_data, dummy = self.account.get_request(auth_uri)
auth_data['uri'] = auth_uri
domain = auth_data['identifier']['value']
if auth_data.get('wildcard', False):

Loading…
Cancel
Save