mirror of
https://github.com/ansible-collections/ansible.posix.git
synced 2026-01-11 15:15:26 +01:00
Merge c8a5dc49af into 5f44339fa5
This commit is contained in:
commit
ab37ce74ec
3 changed files with 74 additions and 24 deletions
|
|
@ -0,0 +1,3 @@
|
||||||
|
---
|
||||||
|
bugfixes:
|
||||||
|
- authorized_key - fix a bug where providing multiple key sources (URLs or file paths) separated by newlines would fail or only process the first source. The module now correctly resolves each source in a newline-separated list before processing the keys (https://github.com/ansible-collections/ansible.posix/issues/684).
|
||||||
|
|
@ -568,32 +568,47 @@ def enforce_state(module, params):
|
||||||
follow = params.get('follow', False)
|
follow = params.get('follow', False)
|
||||||
error_msg = "Error getting key from: %s"
|
error_msg = "Error getting key from: %s"
|
||||||
|
|
||||||
# if the key is a url or file, request it and use it as key source
|
# Split the raw input into individual lines first
|
||||||
if key.startswith("http"):
|
# This is the key to supporting mixed URLs and raw keys
|
||||||
try:
|
raw_sources = [s.strip() for s in key.splitlines() if s.strip()]
|
||||||
resp, info = fetch_url(module, key)
|
final_keys = []
|
||||||
if info['status'] != 200:
|
|
||||||
module.fail_json(msg=error_msg % key)
|
|
||||||
else:
|
|
||||||
key = resp.read()
|
|
||||||
except Exception:
|
|
||||||
module.fail_json(msg=error_msg % key)
|
|
||||||
|
|
||||||
# resp.read gives bytes on python3, convert to native string type
|
for source in raw_sources:
|
||||||
key = to_native(key, errors='surrogate_or_strict')
|
if source.startswith('#'):
|
||||||
|
continue
|
||||||
|
|
||||||
if key.startswith("file"):
|
validate_certs = params.get('validate_certs', True)
|
||||||
# if the key is an absolute path, check for existense and use it as a key source
|
# Identify if this specific line is a URL
|
||||||
key_path = urlparse(key).path
|
if source.startswith(('http://', 'https://')):
|
||||||
if not os.path.exists(key_path):
|
try:
|
||||||
module.fail_json(msg="Path to a key file not found: %s" % key_path)
|
resp, info = fetch_url(module, source, validate_certs=validate_certs)
|
||||||
if not os.path.isfile(key_path):
|
if info['status'] != 200:
|
||||||
module.fail_json(msg="Path to a key is a directory and must be a file: %s" % key_path)
|
module.fail_json(msg=error_msg % source)
|
||||||
try:
|
|
||||||
with open(key_path, 'r') as source_fh:
|
# Fetch the keys from the URL and convert to native string
|
||||||
key = source_fh.read()
|
url_content = to_native(resp.read(), errors='surrogate_or_strict')
|
||||||
except OSError as e:
|
if url_content:
|
||||||
module.fail_json(msg="Failed to read key file %s : %s" % (key_path, to_native(e)))
|
final_keys.append(url_content)
|
||||||
|
except Exception:
|
||||||
|
module.fail_json(msg=error_msg % source)
|
||||||
|
|
||||||
|
# Identify if this specific line is a local file path
|
||||||
|
elif source.startswith("file://"):
|
||||||
|
key_path = urlparse(source).path
|
||||||
|
if not os.path.exists(key_path):
|
||||||
|
module.fail_json(msg="Path to a key file not found: %s" % key_path)
|
||||||
|
try:
|
||||||
|
with open(key_path, 'r') as source_fh:
|
||||||
|
final_keys.append(source_fh.read())
|
||||||
|
except OSError as e:
|
||||||
|
module.fail_json(msg="Failed to read key file %s : %s" % (key_path, to_native(e)))
|
||||||
|
|
||||||
|
# If it's not a URL or a File, it's a raw SSH key
|
||||||
|
else:
|
||||||
|
final_keys.append(source)
|
||||||
|
|
||||||
|
# Join everything back together for the rest of the module's existing logic
|
||||||
|
key = "\n".join(final_keys)
|
||||||
|
|
||||||
# extract individual keys into an array, skipping blank lines and comments
|
# extract individual keys into an array, skipping blank lines and comments
|
||||||
new_keys = [s for s in key.splitlines() if s and not s.startswith('#')]
|
new_keys = [s for s in key.splitlines() if s and not s.startswith('#')]
|
||||||
|
|
|
||||||
|
|
@ -95,3 +95,35 @@
|
||||||
- result.changed == False
|
- result.changed == False
|
||||||
- multiple_keys_comments.stdout == multiple_key_exclusive.strip()
|
- multiple_keys_comments.stdout == multiple_key_exclusive.strip()
|
||||||
- result.key_options == None
|
- result.key_options == None
|
||||||
|
|
||||||
|
- name: Create local key source simulating a URL response
|
||||||
|
ansible.builtin.copy:
|
||||||
|
dest: "{{ output_dir | expanduser }}/simulated_url.txt"
|
||||||
|
content: |
|
||||||
|
ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQDXJ1HrhQEXOexamplekey1fromurl test1@example.com
|
||||||
|
ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIGexamplekey2fromurl test2@example.com
|
||||||
|
mode: "0644"
|
||||||
|
|
||||||
|
- name: Add mixed keys (file source + raw key)
|
||||||
|
ansible.posix.authorized_key:
|
||||||
|
user: root
|
||||||
|
key: |
|
||||||
|
file://{{ output_dir | expanduser }}/simulated_url.txt
|
||||||
|
ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIOMqmqp9pP9pP9pP9pP9pP9pP9pP9pP9pP9pP9pP test@example.com
|
||||||
|
state: present
|
||||||
|
path: "{{ output_dir | expanduser }}/authorized_keys"
|
||||||
|
exclusive: true
|
||||||
|
register: mixed_source_result
|
||||||
|
|
||||||
|
- name: Get the file content for mixed source verification
|
||||||
|
ansible.builtin.command: /bin/cat "{{ output_dir | expanduser }}/authorized_keys"
|
||||||
|
changed_when: false
|
||||||
|
register: mixed_file_content
|
||||||
|
|
||||||
|
- name: Assert mixed sources were merged and processed correctly
|
||||||
|
ansible.builtin.assert:
|
||||||
|
that:
|
||||||
|
- mixed_source_result.changed == True
|
||||||
|
- mixed_file_content.stdout_lines | length == 3
|
||||||
|
- "'test1@example.com' in mixed_file_content.stdout"
|
||||||
|
- "'test@example.com' in mixed_file_content.stdout"
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue