1
0
Fork 0
mirror of https://github.com/ansible-collections/community.general.git synced 2024-09-14 20:13:21 +02:00

Added SHA1 option to maven_artifact (#2662)

* Added SHA1 option

* Add changelog fragment

* Update plugins/modules/packaging/language/maven_artifact.py

Co-authored-by: Felix Fontein <felix@fontein.de>

* Update plugins/modules/packaging/language/maven_artifact.py

Co-authored-by: Felix Fontein <felix@fontein.de>

* Combined hash functions

Co-authored-by: Felix Fontein <felix@fontein.de>

* Update plugins/modules/packaging/language/maven_artifact.py

Co-authored-by: Felix Fontein <felix@fontein.de>

* Update plugins/modules/packaging/language/maven_artifact.py

Co-authored-by: Felix Fontein <felix@fontein.de>

* Removed unused functions (rolled into _local_checksum)

* Update changelogs/fragments/2661-maven_artifact-add-sha1-option.yml

Co-authored-by: Felix Fontein <felix@fontein.de>

Co-authored-by: Felix Fontein <felix@fontein.de>
This commit is contained in:
Gene Gotimer 2021-06-01 16:06:26 -04:00 committed by GitHub
parent 1ad85849af
commit ca1506fb26
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
2 changed files with 46 additions and 28 deletions

View file

@ -0,0 +1,2 @@
minor_changes:
- maven_artifact - added ``checksum_alg`` option to support SHA1 checksums in order to support FIPS systems (https://github.com/ansible-collections/community.general/pull/2662).

View file

@ -129,10 +129,10 @@ options:
verify_checksum: verify_checksum:
type: str type: str
description: description:
- If C(never), the md5 checksum will never be downloaded and verified. - If C(never), the MD5/SHA1 checksum will never be downloaded and verified.
- If C(download), the md5 checksum will be downloaded and verified only after artifact download. This is the default. - If C(download), the MD5/SHA1 checksum will be downloaded and verified only after artifact download. This is the default.
- If C(change), the md5 checksum will be downloaded and verified if the destination already exist, - If C(change), the MD5/SHA1 checksum will be downloaded and verified if the destination already exist,
to verify if they are identical. This was the behaviour before 2.6. Since it downloads the md5 before (maybe) to verify if they are identical. This was the behaviour before 2.6. Since it downloads the checksum before (maybe)
downloading the artifact, and since some repository software, when acting as a proxy/cache, return a 404 error downloading the artifact, and since some repository software, when acting as a proxy/cache, return a 404 error
if the artifact has not been cached yet, it may fail unexpectedly. if the artifact has not been cached yet, it may fail unexpectedly.
If you still need it, you should consider using C(always) instead - if you deal with a checksum, it is better to If you still need it, you should consider using C(always) instead - if you deal with a checksum, it is better to
@ -141,6 +141,15 @@ options:
required: false required: false
default: 'download' default: 'download'
choices: ['never', 'download', 'change', 'always'] choices: ['never', 'download', 'change', 'always']
checksum_alg:
type: str
description:
- If C(md5), checksums will use the MD5 algorithm. This is the default.
- If C(sha1), checksums will use the SHA1 algorithm. This can be used on systems configured to use
FIPS-compliant algorithms, since MD5 will be blocked on such systems.
default: 'md5'
choices: ['md5', 'sha1']
version_added: 3.2.0
directory_mode: directory_mode:
type: str type: str
description: description:
@ -507,7 +516,7 @@ class MavenDownloader:
raise ValueError(failmsg + " because of " + info['msg'] + "for URL " + url_to_use) raise ValueError(failmsg + " because of " + info['msg'] + "for URL " + url_to_use)
return None return None
def download(self, tmpdir, artifact, verify_download, filename=None): def download(self, tmpdir, artifact, verify_download, filename=None, checksum_alg='md5'):
if (not artifact.version and not artifact.version_by_spec) or artifact.version == "latest": if (not artifact.version and not artifact.version_by_spec) or artifact.version == "latest":
artifact = Artifact(artifact.group_id, artifact.artifact_id, self.find_latest_version_available(artifact), None, artifact = Artifact(artifact.group_id, artifact.artifact_id, self.find_latest_version_available(artifact), None,
artifact.classifier, artifact.extension) artifact.classifier, artifact.extension)
@ -528,11 +537,11 @@ class MavenDownloader:
shutil.copyfileobj(response, f) shutil.copyfileobj(response, f)
if verify_download: if verify_download:
invalid_md5 = self.is_invalid_md5(tempname, url) invalid_checksum = self.is_invalid_checksum(tempname, url, checksum_alg)
if invalid_md5: if invalid_checksum:
# if verify_change was set, the previous file would be deleted # if verify_change was set, the previous file would be deleted
os.remove(tempname) os.remove(tempname)
return invalid_md5 return invalid_checksum
except Exception as e: except Exception as e:
os.remove(tempname) os.remove(tempname)
raise e raise e
@ -541,40 +550,45 @@ class MavenDownloader:
shutil.move(tempname, artifact.get_filename(filename)) shutil.move(tempname, artifact.get_filename(filename))
return None return None
def is_invalid_md5(self, file, remote_url): def is_invalid_checksum(self, file, remote_url, checksum_alg='md5'):
if os.path.exists(file): if os.path.exists(file):
local_md5 = self._local_md5(file) local_checksum = self._local_checksum(checksum_alg, file)
if self.local: if self.local:
parsed_url = urlparse(remote_url) parsed_url = urlparse(remote_url)
remote_md5 = self._local_md5(parsed_url.path) remote_checksum = self._local_checksum(checksum_alg, parsed_url.path)
else: else:
try: try:
remote_md5 = to_text(self._getContent(remote_url + '.md5', "Failed to retrieve MD5", False), errors='strict') remote_checksum = to_text(self._getContent(remote_url + '.' + checksum_alg, "Failed to retrieve checksum", False), errors='strict')
except UnicodeError as e: except UnicodeError as e:
return "Cannot retrieve a valid md5 from %s: %s" % (remote_url, to_native(e)) return "Cannot retrieve a valid %s checksum from %s: %s" % (checksum_alg, remote_url, to_native(e))
if(not remote_md5): if not remote_checksum:
return "Cannot find md5 from " + remote_url return "Cannot find %s checksum from %s" % (checksum_alg, remote_url)
try: try:
# Check if remote md5 only contains md5 or md5 + filename # Check if remote checksum only contains md5/sha1 or md5/sha1 + filename
_remote_md5 = remote_md5.split(None)[0] _remote_checksum = remote_checksum.split(None)[0]
remote_md5 = _remote_md5 remote_checksum = _remote_checksum
# remote_md5 is empty so we continue and keep original md5 string # remote_checksum is empty so we continue and keep original checksum string
# This should not happen since we check for remote_md5 before # This should not happen since we check for remote_checksum before
except IndexError: except IndexError:
pass pass
if local_md5.lower() == remote_md5.lower(): if local_checksum.lower() == remote_checksum.lower():
return None return None
else: else:
return "Checksum does not match: we computed " + local_md5 + " but the repository states " + remote_md5 return "Checksum does not match: we computed " + local_checksum + " but the repository states " + remote_checksum
return "Path does not exist: " + file return "Path does not exist: " + file
def _local_md5(self, file): def _local_checksum(self, checksum_alg, file):
md5 = hashlib.md5() if checksum_alg.lower() == 'md5':
hash = hashlib.md5()
elif checksum_alg.lower() == 'sha1':
hash = hashlib.sha1()
else:
raise ValueError("Unknown checksum_alg %s" % checksum_alg)
with io.open(file, 'rb') as f: with io.open(file, 'rb') as f:
for chunk in iter(lambda: f.read(8192), b''): for chunk in iter(lambda: f.read(8192), b''):
md5.update(chunk) hash.update(chunk)
return md5.hexdigest() return hash.hexdigest()
def main(): def main():
@ -599,6 +613,7 @@ def main():
client_key=dict(type="path", required=False), client_key=dict(type="path", required=False),
keep_name=dict(required=False, default=False, type='bool'), keep_name=dict(required=False, default=False, type='bool'),
verify_checksum=dict(required=False, default='download', choices=['never', 'download', 'change', 'always']), verify_checksum=dict(required=False, default='download', choices=['never', 'download', 'change', 'always']),
checksum_alg=dict(required=False, default='md5', choices=['md5', 'sha1']),
directory_mode=dict(type='str'), directory_mode=dict(type='str'),
), ),
add_file_common_args=True, add_file_common_args=True,
@ -639,6 +654,7 @@ def main():
verify_checksum = module.params["verify_checksum"] verify_checksum = module.params["verify_checksum"]
verify_download = verify_checksum in ['download', 'always'] verify_download = verify_checksum in ['download', 'always']
verify_change = verify_checksum in ['change', 'always'] verify_change = verify_checksum in ['change', 'always']
checksum_alg = module.params["checksum_alg"]
downloader = MavenDownloader(module, repository_url, local, headers) downloader = MavenDownloader(module, repository_url, local, headers)
@ -683,12 +699,12 @@ def main():
b_dest = to_bytes(dest, errors='surrogate_or_strict') b_dest = to_bytes(dest, errors='surrogate_or_strict')
if os.path.lexists(b_dest) and ((not verify_change) or not downloader.is_invalid_md5(dest, downloader.find_uri_for_artifact(artifact))): if os.path.lexists(b_dest) and ((not verify_change) or not downloader.is_invalid_checksum(dest, downloader.find_uri_for_artifact(artifact), checksum_alg)):
prev_state = "present" prev_state = "present"
if prev_state == "absent": if prev_state == "absent":
try: try:
download_error = downloader.download(module.tmpdir, artifact, verify_download, b_dest) download_error = downloader.download(module.tmpdir, artifact, verify_download, b_dest, checksum_alg)
if download_error is None: if download_error is None:
changed = True changed = True
else: else: