From 9e1af2d1bce7b30995b46a2fa2992a054c507e3a Mon Sep 17 00:00:00 2001 From: Sam Doran Date: Mon, 9 May 2022 01:24:35 -0400 Subject: [PATCH] onepassword - Get first found config file (#4640) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * Get first found configuration file There are three valid places to get the configuration. https://developer.1password.com/docs/cli/about-biometric-unlock#remove-old-account-information * Use common config class * Add changelog fragment * Explicitly use new style classes for Python 2.7 compatibility This shouldn’t matter for lookups, but does matter for module_utils and modules since Python 2.7 is still supported on the managed node. * Update changelogs/fragments/4065-onepassword-config.yml Co-authored-by: Felix Fontein --- .../fragments/4065-onepassword-config.yml | 2 ++ plugins/lookup/onepassword.py | 13 +++++---- plugins/module_utils/onepassword.py | 29 +++++++++++++++++++ plugins/modules/identity/onepassword_info.py | 7 +++-- 4 files changed, 44 insertions(+), 7 deletions(-) create mode 100644 changelogs/fragments/4065-onepassword-config.yml create mode 100644 plugins/module_utils/onepassword.py diff --git a/changelogs/fragments/4065-onepassword-config.yml b/changelogs/fragments/4065-onepassword-config.yml new file mode 100644 index 0000000000..9d58a0e57f --- /dev/null +++ b/changelogs/fragments/4065-onepassword-config.yml @@ -0,0 +1,2 @@ +bugfixes: + - onepassword - search all valid configuration locations and use the first found (https://github.com/ansible-collections/community.general/pull/4640). diff --git a/plugins/lookup/onepassword.py b/plugins/lookup/onepassword.py index 9f97a90e71..e0be0cd27e 100644 --- a/plugins/lookup/onepassword.py +++ b/plugins/lookup/onepassword.py @@ -45,8 +45,8 @@ DOCUMENTATION = ''' description: Vault containing the item to retrieve (case-insensitive). If absent will search all vaults. notes: - This lookup will use an existing 1Password session if one exists. If not, and you have already - performed an initial sign in (meaning C(~/.op/config exists)), then only the C(master_password) is required. - You may optionally specify C(subdomain) in this scenario, otherwise the last used subdomain will be used by C(op). + performed an initial sign in (meaning C(~/.op/config), C(~/.config/op/config) or C(~/.config/.op/config) exists), then only the + C(master_password) is required. You may optionally specify C(subdomain) in this scenario, otherwise the last used subdomain will be used by C(op). - This lookup can perform an initial login by providing C(subdomain), C(username), C(secret_key), and C(master_password). - Due to the B(very) sensitive nature of these credentials, it is B(highly) recommended that you only pass in the minimal credentials needed at any given time. Also, store these credentials in an Ansible Vault using a key that is equal to or greater in strength @@ -105,12 +105,12 @@ from ansible.plugins.lookup import LookupBase from ansible.errors import AnsibleLookupError from ansible.module_utils.common.text.converters import to_bytes, to_text +from ansible_collections.community.general.plugins.module_utils.onepassword import OnePasswordConfig + class OnePass(object): - def __init__(self, path='op'): self.cli_path = path - self.config_file_path = os.path.expanduser('~/.op/config') self.logged_in = False self.token = None self.subdomain = None @@ -119,9 +119,11 @@ class OnePass(object): self.secret_key = None self.master_password = None + self._config = OnePasswordConfig() + def get_token(self): # If the config file exists, assume an initial signin has taken place and try basic sign in - if os.path.isfile(self.config_file_path): + if os.path.isfile(self._config.config_file_path): if not self.master_password: raise AnsibleLookupError('Unable to sign in to 1Password. master_password is required.') @@ -281,4 +283,5 @@ class LookupModule(LookupBase): values = [] for term in terms: values.append(op.get_field(term, field, section, vault)) + return values diff --git a/plugins/module_utils/onepassword.py b/plugins/module_utils/onepassword.py new file mode 100644 index 0000000000..3a86e22e16 --- /dev/null +++ b/plugins/module_utils/onepassword.py @@ -0,0 +1,29 @@ +# -*- coding: utf-8 -*- +# Simplified BSD License (see licenses/simplified_bsd.txt or https://opensource.org/licenses/BSD-2-Clause) + +from __future__ import (absolute_import, division, print_function) +__metaclass__ = type + +import os + + +class OnePasswordConfig(object): + _config_file_paths = ( + "~/.op/config", + "~/.config/op/config", + "~/.config/.op/config", + ) + + def __init__(self): + self._config_file_path = "" + + @property + def config_file_path(self): + if self._config_file_path: + return self._config_file_path + + for path in self._config_file_paths: + realpath = os.path.expanduser(path) + if os.path.exists(realpath): + self._config_file_path = realpath + return self._config_file_path diff --git a/plugins/modules/identity/onepassword_info.py b/plugins/modules/identity/onepassword_info.py index 7170a33aed..6621092303 100644 --- a/plugins/modules/identity/onepassword_info.py +++ b/plugins/modules/identity/onepassword_info.py @@ -166,6 +166,8 @@ from subprocess import Popen, PIPE from ansible.module_utils.common.text.converters import to_bytes, to_native from ansible.module_utils.basic import AnsibleModule +from ansible_collections.community.general.plugins.module_utils.onepassword import OnePasswordConfig + class AnsibleModuleError(Exception): def __init__(self, results): @@ -179,7 +181,6 @@ class OnePasswordInfo(object): def __init__(self): self.cli_path = module.params.get('cli_path') - self.config_file_path = '~/.op/config' self.auto_login = module.params.get('auto_login') self.logged_in = False self.token = None @@ -187,6 +188,8 @@ class OnePasswordInfo(object): terms = module.params.get('search_terms') self.terms = self.parse_search_terms(terms) + self._config = OnePasswordConfig() + def _run(self, args, expected_rc=0, command_input=None, ignore_errors=False): if self.token: # Adds the session token to all commands if we're logged in. @@ -299,7 +302,7 @@ class OnePasswordInfo(object): def get_token(self): # If the config file exists, assume an initial signin has taken place and try basic sign in - if os.path.isfile(self.config_file_path): + if os.path.isfile(self._config.config_file_path): if self.auto_login is not None: