Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[PR #5851/7b8b73f1 backport][stable-6] Add support to Bitwarden Lookup for filtering results by collection (#5849) #5904

Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
minor_changes:
- bitwarden lookup plugin - implement filtering results by ``collection_id`` parameter (https://github.com/ansible-collections/community.general/issues/5849).
32 changes: 25 additions & 7 deletions plugins/lookup/bitwarden.py
Original file line number Diff line number Diff line change
Expand Up @@ -28,8 +28,12 @@
default: name
version_added: 5.7.0
field:
description: Field to fetch; leave unset to fetch whole response.
description: Field to fetch. Leave unset to fetch whole response.
type: str
collection_id:
description: Collection ID to filter results by collection. Leave unset to skip filtering.
type: str
version_added: 6.3.0
"""

EXAMPLES = """
Expand All @@ -43,6 +47,11 @@
msg: >-
{{ lookup('community.general.bitwarden', 'bafba515-af11-47e6-abe3-af1200cd18b2', search='id', field='password') }}

- name: "Get 'password' from Bitwarden record named 'a_test' from collection"
ansible.builtin.debug:
msg: >-
{{ lookup('community.general.bitwarden', 'a_test', field='password', collection_id='bafba515-af11-47e6-abe3-af1200cd18b2') }}

- name: "Get full Bitwarden record named 'a_test'"
ansible.builtin.debug:
msg: >-
Expand Down Expand Up @@ -96,23 +105,31 @@ def _run(self, args, stdin=None, expected_rc=0):
raise BitwardenException(err)
return to_text(out, errors='surrogate_or_strict'), to_text(err, errors='surrogate_or_strict')

def _get_matches(self, search_value, search_field):
def _get_matches(self, search_value, search_field, collection_id):
"""Return matching records whose search_field is equal to key.
"""
out, err = self._run(['list', 'items', '--search', search_value])

# Prepare set of params for Bitwarden CLI
params = ['list', 'items', '--search', search_value]

if collection_id:
params.extend(['--collectionid', collection_id])

out, err = self._run(params)

# This includes things that matched in different fields.
initial_matches = AnsibleJSONDecoder().raw_decode(out)[0]

# Filter to only include results from the right field.
return [item for item in initial_matches if item[search_field] == search_value]

def get_field(self, field, search_value, search_field="name"):
"""Return a list of the specified field for records whose search_field match search_value.
def get_field(self, field, search_value, search_field="name", collection_id=None):
"""Return a list of the specified field for records whose search_field match search_value
and filtered by collection if collection has been provided.

If field is None, return the whole record for each match.
"""
matches = self._get_matches(search_value, search_field)
matches = self._get_matches(search_value, search_field, collection_id)

if field in ['autofillOnPageLoad', 'password', 'passwordRevisionDate', 'totp', 'uris', 'username']:
return [match['login'][field] for match in matches]
Expand All @@ -135,10 +152,11 @@ def run(self, terms, variables=None, **kwargs):
self.set_options(var_options=variables, direct=kwargs)
field = self.get_option('field')
search_field = self.get_option('search')
collection_id = self.get_option('collection_id')
if not _bitwarden.unlocked:
raise AnsibleError("Bitwarden Vault locked. Run 'bw unlock'.")

return [_bitwarden.get_field(field, term, search_field) for term in terms]
return [_bitwarden.get_field(field, term, search_field, collection_id) for term in terms]


_bitwarden = Bitwarden()
2 changes: 1 addition & 1 deletion tests/unit/plugins/lookup/test_bitwarden.py
Original file line number Diff line number Diff line change
Expand Up @@ -113,7 +113,7 @@ class MockBitwarden(Bitwarden):

unlocked = True

def _get_matches(self, search_value, search_field="name"):
def _get_matches(self, search_value, search_field="name", collection_id=None):
return list(filter(lambda record: record[search_field] == search_value, MOCK_RECORDS))


Expand Down