From eb8b3a8479ec82ad622f86ac46f3e9cc083952b8 Mon Sep 17 00:00:00 2001
From: Edwin Hermans <edwin@madtech.cx>
Date: Mon, 17 Aug 2020 12:21:15 -0400
Subject: [PATCH] get_url - Allow checksum file to be local file:// url
 (#71205)

This would be a partial solution for #69364 in that the SHASUMS file can be downloaded and gpg verified but then used from the downloaded location to verify the get_url's file.
* Make checksum url parsing more explicit

Use urlsplit to test if the checksum string has a (currently tested and) supported url scheme.

* Fix whitespace
* Changelog fragment
* Added tests
* Fix typo in test setup
---
 .../71205_get_url_allow_checksum_file_url.yml       |  2 ++
 lib/ansible/modules/get_url.py                      | 10 +++++++++-
 test/integration/targets/get_url/tasks/main.yml     | 13 +++++++++++++
 3 files changed, 24 insertions(+), 1 deletion(-)
 create mode 100644 changelogs/fragments/71205_get_url_allow_checksum_file_url.yml

diff --git a/changelogs/fragments/71205_get_url_allow_checksum_file_url.yml b/changelogs/fragments/71205_get_url_allow_checksum_file_url.yml
new file mode 100644
index 00000000000..ac3b852cf84
--- /dev/null
+++ b/changelogs/fragments/71205_get_url_allow_checksum_file_url.yml
@@ -0,0 +1,2 @@
+minor_changes:
+  - get_url - allow checksum urls to point to file:// resources, moving scheme test to function
diff --git a/lib/ansible/modules/get_url.py b/lib/ansible/modules/get_url.py
index c5f3411d35c..b031a43b552 100644
--- a/lib/ansible/modules/get_url.py
+++ b/lib/ansible/modules/get_url.py
@@ -416,6 +416,14 @@ def extract_filename_from_headers(headers):
     return res
 
 
+def is_url(checksum):
+    """
+    Returns True if checksum value has supported URL scheme, else False."""
+    supported_schemes = ('http', 'https', 'ftp', 'file')
+
+    return urlsplit(checksum).scheme in supported_schemes
+
+
 # ==============================================================
 # main
 
@@ -487,7 +495,7 @@ def main():
         except ValueError:
             module.fail_json(msg="The checksum parameter has to be in format <algorithm>:<checksum>", **result)
 
-        if checksum.startswith('http://') or checksum.startswith('https://') or checksum.startswith('ftp://'):
+        if is_url(checksum):
             checksum_url = checksum
             # download checksum file to checksum_tmpsrc
             checksum_tmpsrc, checksum_info = url_get(module, checksum_url, dest, use_proxy, last_mod_time, force, timeout, headers, tmp_dest)
diff --git a/test/integration/targets/get_url/tasks/main.yml b/test/integration/targets/get_url/tasks/main.yml
index 052bde222a2..6adb3db74c7 100644
--- a/test/integration/targets/get_url/tasks/main.yml
+++ b/test/integration/targets/get_url/tasks/main.yml
@@ -407,15 +407,28 @@
     path: "{{ remote_tmp_dir }}/27617sha256_with_dot.txt"
   register: stat_result_sha256_with_dot
 
+- name: download src with sha256 checksum url with file scheme
+  get_url:
+    url: 'http://localhost:{{ http_port }}/27617.txt'
+    dest: '{{ remote_tmp_dir }}/27617sha256_with_file_scheme.txt'
+    checksum: 'sha256:file://{{ files_dir }}/sha256sum.txt'
+  register: result_sha256_with_file_scheme
+
+- stat:
+    path: "{{ remote_tmp_dir }}/27617sha256_with_dot.txt"
+  register: stat_result_sha256_with_file_scheme
+
 - name: Assert that the file was downloaded
   assert:
     that:
       - result_sha1 is changed
       - result_sha256 is changed
       - result_sha256_with_dot is changed
+      - result_sha256_with_file_scheme is changed
       - "stat_result_sha1.stat.exists == true"
       - "stat_result_sha256.stat.exists == true"
       - "stat_result_sha256_with_dot.stat.exists == true"
+      - "stat_result_sha256_with_file_scheme.stat.exists == true"
 
 #https://github.com/ansible/ansible/issues/16191
 - name: Test url split with no filename