Merge pull request #50160 from Rylon/backport/2.7/47213

Fix an issue retrieving some types of 1Password items. (#47213)
This commit is contained in:
Ryan Conway 2019-01-18 20:49:51 +00:00 committed by Toshio Kuratomi
parent 016bc83b58
commit 41214d4426
2 changed files with 58 additions and 1 deletions

View file

@ -0,0 +1,2 @@
bugfixes:
- onepassword_facts - Fix an issue looking up some 1Password items which have a 'password' attribute alongside the 'fields' attribute, not inside it.

View file

@ -138,9 +138,18 @@ import os
import re
from subprocess import Popen, PIPE
from ansible.module_utils._text import to_bytes, to_native
from ansible.module_utils.basic import AnsibleModule
class AnsibleModuleError(Exception):
def __init__(self, results):
self.results = results
def __repr__(self):
return self.results
class OnePasswordFacts(object):
def __init__(self):
@ -149,7 +158,53 @@ class OnePasswordFacts(object):
self.token = {}
terms = module.params.get('search_terms')
self.terms = self.parse_search_terms(module.params.get('search_terms'))
self.terms = self.parse_search_terms(terms)
def _run(self, args, expected_rc=0, command_input=None, ignore_errors=False):
command = [self.cli_path] + args
p = Popen(command, stdout=PIPE, stderr=PIPE, stdin=PIPE)
out, err = p.communicate(input=command_input)
rc = p.wait()
if not ignore_errors and rc != expected_rc:
raise AnsibleModuleError(to_native(err))
return rc, out, err
def _parse_field(self, data_json, item_id, field_name, section_title=None):
data = json.loads(data_json)
if ('documentAttributes' in data['details']):
# This is actually a document, let's fetch the document data instead!
document = self._run(["get", "document", data['overview']['title']])
return {'document': document[0].strip()}
else:
# This is not a document, let's try to find the requested field
# Some types of 1Password items have a 'password' field directly alongside the 'fields' attribute,
# not inside it, so we need to check there first.
if (field_name in data['details']):
return {field_name: data['details'][field_name]}
# Otherwise we continue looking inside the 'fields' attribute for the specified field.
else:
if section_title is None:
for field_data in data['details'].get('fields', []):
if field_data.get('name').lower() == field_name.lower():
return {field_name: field_data.get('value', '')}
# Not found it yet, so now lets see if there are any sections defined
# and search through those for the field. If a section was given, we skip
# any non-matching sections, otherwise we search them all until we find the field.
for section_data in data['details'].get('sections', []):
if section_title is not None and section_title.lower() != section_data['title'].lower():
continue
for field_data in section_data.get('fields', []):
if field_data.get('t').lower() == field_name.lower():
return {field_name: field_data.get('v', '')}
# We will get here if the field could not be found in any section and the item wasn't a document to be downloaded.
optional_section_title = '' if section_title is None else " in the section '%s'" % section_title
module.fail_json(msg="Unable to find an item in 1Password named '%s' with the field '%s'%s." % (item_id, field_name, optional_section_title))
def parse_search_terms(self, terms):
processed_terms = []