uri - add ca_path parameter (#71979)

* add changelog fragment for #71979 (ca_path for uri)
* add integration tests for ca_path in the uri module
* return path of ca cert instead of its content
* connect to port 444 on self_signed_host
  and use quay.io/ansible/http-test-container:1.3.0
* state that the certificate in ca_path is used for validation
This commit is contained in:
Florian Heiderich 2021-02-05 15:40:52 +01:00 committed by GitHub
parent 82cdd7e735
commit 8d6136eab9
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
4 changed files with 55 additions and 7 deletions

View file

@ -0,0 +1,2 @@
minor_changes:
- uri - add ``ca_path`` argument to allow specification of a CA certificate (https://github.com/ansible/ansible/pull/71979).

View file

@ -923,9 +923,7 @@ class SSLValidationHandler(urllib_request.BaseHandler):
to_native(f.read(), errors='surrogate_or_strict') to_native(f.read(), errors='surrogate_or_strict')
) )
) )
else: return self.ca_path, cadata, paths_checked
ca_certs.append(f.read())
return ca_certs, cadata, paths_checked
if not HAS_SSLCONTEXT: if not HAS_SSLCONTEXT:
paths_checked.append('/etc/ssl/certs') paths_checked.append('/etc/ssl/certs')

View file

@ -141,6 +141,11 @@ options:
- If I(client_cert) contains both the certificate and key, this option is not required. - If I(client_cert) contains both the certificate and key, this option is not required.
type: path type: path
version_added: '2.4' version_added: '2.4'
ca_path:
description:
- PEM formatted file that contains a CA certificate to be used for validation
type: path
version_added: '2.11'
src: src:
description: description:
- Path to file to be submitted to the remote server. - Path to file to be submitted to the remote server.
@ -548,13 +553,12 @@ def form_urlencoded(body):
return body return body
def uri(module, url, dest, body, body_format, method, headers, socket_timeout): def uri(module, url, dest, body, body_format, method, headers, socket_timeout, ca_path):
# is dest is set and is a directory, let's check if we get redirected and # is dest is set and is a directory, let's check if we get redirected and
# set the filename from that url # set the filename from that url
redirected = False redirected = False
redir_info = {} redir_info = {}
r = {} r = {}
src = module.params['src'] src = module.params['src']
if src: if src:
try: try:
@ -594,6 +598,7 @@ def uri(module, url, dest, body, body_format, method, headers, socket_timeout):
resp, info = fetch_url(module, url, data=data, headers=headers, resp, info = fetch_url(module, url, data=data, headers=headers,
method=method, timeout=socket_timeout, unix_socket=module.params['unix_socket'], method=method, timeout=socket_timeout, unix_socket=module.params['unix_socket'],
ca_path=ca_path,
**kwargs) **kwargs)
try: try:
@ -636,6 +641,7 @@ def main():
headers=dict(type='dict', default={}), headers=dict(type='dict', default={}),
unix_socket=dict(type='path'), unix_socket=dict(type='path'),
remote_src=dict(type='bool', default=False), remote_src=dict(type='bool', default=False),
ca_path=dict(type='path', default=None),
) )
module = AnsibleModule( module = AnsibleModule(
@ -658,7 +664,7 @@ def main():
removes = module.params['removes'] removes = module.params['removes']
status_code = [int(x) for x in list(module.params['status_code'])] status_code = [int(x) for x in list(module.params['status_code'])]
socket_timeout = module.params['timeout'] socket_timeout = module.params['timeout']
ca_path = module.params['ca_path']
dict_headers = module.params['headers'] dict_headers = module.params['headers']
if not re.match('^[A-Z]+$', method): if not re.match('^[A-Z]+$', method):
@ -702,7 +708,7 @@ def main():
# Make the request # Make the request
start = datetime.datetime.utcnow() start = datetime.datetime.utcnow()
resp, content, dest = uri(module, url, dest, body, body_format, method, resp, content, dest = uri(module, url, dest, body, body_format, method,
dict_headers, socket_timeout) dict_headers, socket_timeout, ca_path)
resp['elapsed'] = (datetime.datetime.utcnow() - start).seconds resp['elapsed'] = (datetime.datetime.utcnow() - start).seconds
resp['status'] = int(resp['status']) resp['status'] = int(resp['status'])
resp['changed'] = False resp['changed'] = False

View file

@ -131,6 +131,48 @@
- "stat_result.stat.exists == true" - "stat_result.stat.exists == true"
- "result.changed == true" - "result.changed == true"
- name: "get ca certificate {{ self_signed_host }}"
get_url:
url: "http://{{ httpbin_host }}/ca2cert.pem"
dest: "{{ remote_tmp_dir }}/ca2cert.pem"
- name: test https fetch to a site with self signed certificate using ca_path
uri:
url: "https://{{ self_signed_host }}:444/"
dest: "{{ output_dir }}/self-signed_using_ca_path.html"
ca_path: "{{ remote_tmp_dir }}/ca2cert.pem"
validate_certs: yes
register: result
- stat:
path: "{{ output_dir }}/self-signed_using_ca_path.html"
register: stat_result
- name: Assert that the file was downloaded
assert:
that:
- "stat_result.stat.exists == true"
- "result.changed == true"
- name: test https fetch to a site with self signed certificate without using ca_path
uri:
url: "https://{{ self_signed_host }}:444/"
dest: "{{ output_dir }}/self-signed-without_using_ca_path.html"
validate_certs: yes
register: result
ignore_errors: true
- stat:
path: "{{ output_dir }}/self-signed-without_using_ca_path.html"
register: stat_result
- name: Assure that https access to a host with self-signed certificate without providing ca_path fails
assert:
that:
- "stat_result.stat.exists == false"
- result is failed
- "'certificate verify failed' in result.msg"
- name: test redirect without follow_redirects - name: test redirect without follow_redirects
uri: uri:
url: 'https://{{ httpbin_host }}/redirect/2' url: 'https://{{ httpbin_host }}/redirect/2'