Initial commit

This commit is contained in:
Ansible Core Team 2020-03-09 09:11:07 +00:00
commit aebc1b03fd
4861 changed files with 812621 additions and 0 deletions

View file

@ -0,0 +1,292 @@
#!/usr/bin/python
# -*- coding: utf-8 -*-
# Copyright: (c) 2016, Peter Sagerson <psagers@ignorare.net>
# Copyright: (c) 2016, Jiri Tyr <jiri.tyr@gmail.com>
# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
from __future__ import absolute_import, division, print_function
__metaclass__ = type
ANSIBLE_METADATA = {
'metadata_version': '1.1',
'status': ['deprecated'],
'supported_by': 'community'
}
DOCUMENTATION = r'''
---
module: ldap_attr
short_description: Add or remove LDAP attribute values
description:
- Add or remove LDAP attribute values.
notes:
- This only deals with attributes on existing entries. To add or remove
whole entries, see M(ldap_entry).
- The default authentication settings will attempt to use a SASL EXTERNAL
bind over a UNIX domain socket. This works well with the default Ubuntu
install for example, which includes a cn=peercred,cn=external,cn=auth ACL
rule allowing root to modify the server configuration. If you need to use
a simple bind to access your server, pass the credentials in I(bind_dn)
and I(bind_pw).
- For I(state=present) and I(state=absent), all value comparisons are
performed on the server for maximum accuracy. For I(state=exact), values
have to be compared in Python, which obviously ignores LDAP matching
rules. This should work out in most cases, but it is theoretically
possible to see spurious changes when target and actual values are
semantically identical but lexically distinct.
deprecated:
removed_in: '2.14'
why: 'The current "ldap_attr" module does not support LDAP attribute insertions or deletions with objectClass dependencies.'
alternative: 'Use M(ldap_attrs) instead. Deprecated in 2.10.'
author:
- Jiri Tyr (@jtyr)
requirements:
- python-ldap
options:
name:
description:
- The name of the attribute to modify.
type: str
required: true
state:
description:
- The state of the attribute values.
- If C(present), all given values will be added if they're missing.
- If C(absent), all given values will be removed if present.
- If C(exact), the set of values will be forced to exactly those provided and no others.
- If I(state=exact) and I(value) is an empty list, all values for this attribute will be removed.
type: str
choices: [ absent, exact, present ]
default: present
values:
description:
- The value(s) to add or remove. This can be a string or a list of
strings. The complex argument format is required in order to pass
a list of strings (see examples).
type: raw
required: true
params:
description:
- Additional module parameters.
type: dict
extends_documentation_fragment:
- community.general.ldap.documentation
'''
EXAMPLES = r'''
- name: Configure directory number 1 for example.com
ldap_attr:
dn: olcDatabase={1}hdb,cn=config
name: olcSuffix
values: dc=example,dc=com
state: exact
# The complex argument format is required here to pass a list of ACL strings.
- name: Set up the ACL
ldap_attr:
dn: olcDatabase={1}hdb,cn=config
name: olcAccess
values:
- >-
{0}to attrs=userPassword,shadowLastChange
by self write
by anonymous auth
by dn="cn=admin,dc=example,dc=com" write
by * none'
- >-
{1}to dn.base="dc=example,dc=com"
by dn="cn=admin,dc=example,dc=com" write
by * read
state: exact
- name: Declare some indexes
ldap_attr:
dn: olcDatabase={1}hdb,cn=config
name: olcDbIndex
values: "{{ item }}"
with_items:
- objectClass eq
- uid eq
- name: Set up a root user, which we can use later to bootstrap the directory
ldap_attr:
dn: olcDatabase={1}hdb,cn=config
name: "{{ item.key }}"
values: "{{ item.value }}"
state: exact
with_dict:
olcRootDN: cn=root,dc=example,dc=com
olcRootPW: "{SSHA}tabyipcHzhwESzRaGA7oQ/SDoBZQOGND"
- name: Get rid of an unneeded attribute
ldap_attr:
dn: uid=jdoe,ou=people,dc=example,dc=com
name: shadowExpire
values: []
state: exact
server_uri: ldap://localhost/
bind_dn: cn=admin,dc=example,dc=com
bind_pw: password
#
# The same as in the previous example but with the authentication details
# stored in the ldap_auth variable:
#
# ldap_auth:
# server_uri: ldap://localhost/
# bind_dn: cn=admin,dc=example,dc=com
# bind_pw: password
- name: Get rid of an unneeded attribute
ldap_attr:
dn: uid=jdoe,ou=people,dc=example,dc=com
name: shadowExpire
values: []
state: exact
params: "{{ ldap_auth }}"
'''
RETURN = r'''
modlist:
description: list of modified parameters
returned: success
type: list
sample: '[[2, "olcRootDN", ["cn=root,dc=example,dc=com"]]]'
'''
import traceback
from ansible.module_utils.basic import AnsibleModule, missing_required_lib
from ansible.module_utils._text import to_native, to_bytes
from ansible_collections.community.general.plugins.module_utils.ldap import LdapGeneric, gen_specs
LDAP_IMP_ERR = None
try:
import ldap
HAS_LDAP = True
except ImportError:
LDAP_IMP_ERR = traceback.format_exc()
HAS_LDAP = False
class LdapAttr(LdapGeneric):
def __init__(self, module):
LdapGeneric.__init__(self, module)
# Shortcuts
self.name = self.module.params['name']
self.state = self.module.params['state']
# Normalize values
if isinstance(self.module.params['values'], list):
self.values = list(map(to_bytes, self.module.params['values']))
else:
self.values = [to_bytes(self.module.params['values'])]
def add(self):
values_to_add = list(filter(self._is_value_absent, self.values))
if len(values_to_add) > 0:
modlist = [(ldap.MOD_ADD, self.name, values_to_add)]
else:
modlist = []
return modlist
def delete(self):
values_to_delete = list(filter(self._is_value_present, self.values))
if len(values_to_delete) > 0:
modlist = [(ldap.MOD_DELETE, self.name, values_to_delete)]
else:
modlist = []
return modlist
def exact(self):
try:
results = self.connection.search_s(
self.dn, ldap.SCOPE_BASE, attrlist=[self.name])
except ldap.LDAPError as e:
self.fail("Cannot search for attribute %s" % self.name, e)
current = results[0][1].get(self.name, [])
modlist = []
if frozenset(self.values) != frozenset(current):
if len(current) == 0:
modlist = [(ldap.MOD_ADD, self.name, self.values)]
elif len(self.values) == 0:
modlist = [(ldap.MOD_DELETE, self.name, None)]
else:
modlist = [(ldap.MOD_REPLACE, self.name, self.values)]
return modlist
def _is_value_present(self, value):
""" True if the target attribute has the given value. """
try:
is_present = bool(
self.connection.compare_s(self.dn, self.name, value))
except ldap.NO_SUCH_ATTRIBUTE:
is_present = False
return is_present
def _is_value_absent(self, value):
""" True if the target attribute doesn't have the given value. """
return not self._is_value_present(value)
def main():
module = AnsibleModule(
argument_spec=gen_specs(
name=dict(type='str', required=True),
params=dict(type='dict'),
state=dict(type='str', default='present', choices=['absent', 'exact', 'present']),
values=dict(type='raw', required=True),
),
supports_check_mode=True,
)
if not HAS_LDAP:
module.fail_json(msg=missing_required_lib('python-ldap'),
exception=LDAP_IMP_ERR)
# Update module parameters with user's parameters if defined
if 'params' in module.params and isinstance(module.params['params'], dict):
module.params.update(module.params['params'])
# Remove the params
module.params.pop('params', None)
# Instantiate the LdapAttr object
ldap = LdapAttr(module)
state = module.params['state']
# Perform action
if state == 'present':
modlist = ldap.add()
elif state == 'absent':
modlist = ldap.delete()
elif state == 'exact':
modlist = ldap.exact()
changed = False
if len(modlist) > 0:
changed = True
if not module.check_mode:
try:
ldap.connection.modify_s(ldap.dn, modlist)
except Exception as e:
module.fail_json(msg="Attribute action failed.", details=to_native(e))
module.exit_json(changed=changed, modlist=modlist)
if __name__ == '__main__':
main()

View file

@ -0,0 +1,324 @@
#!/usr/bin/python
# -*- coding: utf-8 -*-
# Copyright: (c) 2019, Maciej Delmanowski <drybjed@gmail.com>
# Copyright: (c) 2017, Alexander Korinek <noles@a3k.net>
# Copyright: (c) 2016, Peter Sagerson <psagers@ignorare.net>
# Copyright: (c) 2016, Jiri Tyr <jiri.tyr@gmail.com>
# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
from __future__ import absolute_import, division, print_function
__metaclass__ = type
ANSIBLE_METADATA = {
'metadata_version': '1.1',
'status': ['preview'],
'supported_by': 'community'
}
DOCUMENTATION = r'''
---
module: ldap_attrs
short_description: Add or remove multiple LDAP attribute values
description:
- Add or remove multiple LDAP attribute values.
notes:
- This only deals with attributes on existing entries. To add or remove
whole entries, see M(ldap_entry).
- The default authentication settings will attempt to use a SASL EXTERNAL
bind over a UNIX domain socket. This works well with the default Ubuntu
install for example, which includes a cn=peercred,cn=external,cn=auth ACL
rule allowing root to modify the server configuration. If you need to use
a simple bind to access your server, pass the credentials in I(bind_dn)
and I(bind_pw).
- For I(state=present) and I(state=absent), all value comparisons are
performed on the server for maximum accuracy. For I(state=exact), values
have to be compared in Python, which obviously ignores LDAP matching
rules. This should work out in most cases, but it is theoretically
possible to see spurious changes when target and actual values are
semantically identical but lexically distinct.
author:
- Jiri Tyr (@jtyr)
- Alexander Korinek (@noles)
- Maciej Delmanowski (@drybjed)
requirements:
- python-ldap
options:
state:
required: false
type: str
choices: [present, absent, exact]
default: present
description:
- The state of the attribute values. If C(present), all given attribute
values will be added if they're missing. If C(absent), all given
attribute values will be removed if present. If C(exact), the set of
attribute values will be forced to exactly those provided and no others.
If I(state=exact) and the attribute I(value) is empty, all values for
this attribute will be removed.
attributes:
required: true
type: dict
description:
- The attribute(s) and value(s) to add or remove. The complex argument format is required in order to pass
a list of strings (see examples).
ordered:
required: false
type: bool
default: 'no'
description:
- If C(yes), prepend list values with X-ORDERED index numbers in all
attributes specified in the current task. This is useful mostly with
I(olcAccess) attribute to easily manage LDAP Access Control Lists.
extends_documentation_fragment:
- community.general.ldap.documentation
'''
EXAMPLES = r'''
- name: Configure directory number 1 for example.com
ldap_attrs:
dn: olcDatabase={1}hdb,cn=config
attributes:
olcSuffix: dc=example,dc=com
state: exact
# The complex argument format is required here to pass a list of ACL strings.
- name: Set up the ACL
ldap_attrs:
dn: olcDatabase={1}hdb,cn=config
attributes:
olcAccess:
- >-
{0}to attrs=userPassword,shadowLastChange
by self write
by anonymous auth
by dn="cn=admin,dc=example,dc=com" write
by * none'
- >-
{1}to dn.base="dc=example,dc=com"
by dn="cn=admin,dc=example,dc=com" write
by * read
state: exact
# An alternative approach with automatic X-ORDERED numbering
- name: Set up the ACL
ldap_attrs:
dn: olcDatabase={1}hdb,cn=config
attributes:
olcAccess:
- >-
to attrs=userPassword,shadowLastChange
by self write
by anonymous auth
by dn="cn=admin,dc=example,dc=com" write
by * none'
- >-
to dn.base="dc=example,dc=com"
by dn="cn=admin,dc=example,dc=com" write
by * read
ordered: yes
state: exact
- name: Declare some indexes
ldap_attrs:
dn: olcDatabase={1}hdb,cn=config
attributes:
olcDbIndex:
- objectClass eq
- uid eq
- name: Set up a root user, which we can use later to bootstrap the directory
ldap_attrs:
dn: olcDatabase={1}hdb,cn=config
attributes:
olcRootDN: cn=root,dc=example,dc=com
olcRootPW: "{SSHA}tabyipcHzhwESzRaGA7oQ/SDoBZQOGND"
state: exact
- name: Remove an attribute with a specific value
ldap_attrs:
dn: uid=jdoe,ou=people,dc=example,dc=com
attributes:
description: "An example user account"
state: absent
server_uri: ldap://localhost/
bind_dn: cn=admin,dc=example,dc=com
bind_pw: password
- name: Remove specified attribute(s) from an entry
ldap_attrs:
dn: uid=jdoe,ou=people,dc=example,dc=com
attributes:
description: []
state: exact
server_uri: ldap://localhost/
bind_dn: cn=admin,dc=example,dc=com
bind_pw: password
'''
RETURN = r'''
modlist:
description: list of modified parameters
returned: success
type: list
sample: '[[2, "olcRootDN", ["cn=root,dc=example,dc=com"]]]'
'''
import traceback
from ansible.module_utils.basic import AnsibleModule, missing_required_lib
from ansible.module_utils._text import to_native, to_bytes
from ansible_collections.community.general.plugins.module_utils.ldap import LdapGeneric, gen_specs
import re
LDAP_IMP_ERR = None
try:
import ldap
HAS_LDAP = True
except ImportError:
LDAP_IMP_ERR = traceback.format_exc()
HAS_LDAP = False
class LdapAttrs(LdapGeneric):
def __init__(self, module):
LdapGeneric.__init__(self, module)
# Shortcuts
self.attrs = self.module.params['attributes']
self.state = self.module.params['state']
self.ordered = self.module.params['ordered']
def _order_values(self, values):
""" Preprend X-ORDERED index numbers to attribute's values. """
ordered_values = []
if isinstance(values, list):
for index, value in enumerate(values):
cleaned_value = re.sub(r'^\{\d+\}', '', value)
ordered_values.append('{' + str(index) + '}' + cleaned_value)
return ordered_values
def _normalize_values(self, values):
""" Normalize attribute's values. """
norm_values = []
if isinstance(values, list):
if self.ordered:
norm_values = list(map(to_bytes,
self._order_values(list(map(str,
values)))))
else:
norm_values = list(map(to_bytes, values))
else:
norm_values = [to_bytes(str(values))]
return norm_values
def add(self):
modlist = []
for name, values in self.module.params['attributes'].items():
norm_values = self._normalize_values(values)
for value in norm_values:
if self._is_value_absent(name, value):
modlist.append((ldap.MOD_ADD, name, value))
return modlist
def delete(self):
modlist = []
for name, values in self.module.params['attributes'].items():
norm_values = self._normalize_values(values)
for value in norm_values:
if self._is_value_present(name, value):
modlist.append((ldap.MOD_DELETE, name, value))
return modlist
def exact(self):
modlist = []
for name, values in self.module.params['attributes'].items():
norm_values = self._normalize_values(values)
try:
results = self.connection.search_s(
self.dn, ldap.SCOPE_BASE, attrlist=[name])
except ldap.LDAPError as e:
self.fail("Cannot search for attribute %s" % name, e)
current = results[0][1].get(name, [])
if frozenset(norm_values) != frozenset(current):
if len(current) == 0:
modlist.append((ldap.MOD_ADD, name, norm_values))
elif len(norm_values) == 0:
modlist.append((ldap.MOD_DELETE, name, None))
else:
modlist.append((ldap.MOD_REPLACE, name, norm_values))
return modlist
def _is_value_present(self, name, value):
""" True if the target attribute has the given value. """
try:
is_present = bool(
self.connection.compare_s(self.dn, name, value))
except ldap.NO_SUCH_ATTRIBUTE:
is_present = False
return is_present
def _is_value_absent(self, name, value):
""" True if the target attribute doesn't have the given value. """
return not self._is_value_present(name, value)
def main():
module = AnsibleModule(
argument_spec=gen_specs(
attributes=dict(type='dict', required=True),
ordered=dict(type='bool', default=False, required=False),
state=dict(type='str', default='present', choices=['absent', 'exact', 'present']),
),
supports_check_mode=True,
)
if not HAS_LDAP:
module.fail_json(msg=missing_required_lib('python-ldap'),
exception=LDAP_IMP_ERR)
# Instantiate the LdapAttr object
ldap = LdapAttrs(module)
state = module.params['state']
# Perform action
if state == 'present':
modlist = ldap.add()
elif state == 'absent':
modlist = ldap.delete()
elif state == 'exact':
modlist = ldap.exact()
changed = False
if len(modlist) > 0:
changed = True
if not module.check_mode:
try:
ldap.connection.modify_s(ldap.dn, modlist)
except Exception as e:
module.fail_json(msg="Attribute action failed.", details=to_native(e))
module.exit_json(changed=changed, modlist=modlist)
if __name__ == '__main__':
main()

View file

@ -0,0 +1,252 @@
#!/usr/bin/python
# -*- coding: utf-8 -*-
# Copyright: (c) 2016, Peter Sagerson <psagers@ignorare.net>
# Copyright: (c) 2016, Jiri Tyr <jiri.tyr@gmail.com>
#
# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
from __future__ import absolute_import, division, print_function
__metaclass__ = type
ANSIBLE_METADATA = {
'metadata_version': '1.1',
'status': ['preview'],
'supported_by': 'community'
}
DOCUMENTATION = '''
---
module: ldap_entry
short_description: Add or remove LDAP entries.
description:
- Add or remove LDAP entries. This module only asserts the existence or
non-existence of an LDAP entry, not its attributes. To assert the
attribute values of an entry, see M(ldap_attr).
notes:
- The default authentication settings will attempt to use a SASL EXTERNAL
bind over a UNIX domain socket. This works well with the default Ubuntu
install for example, which includes a cn=peercred,cn=external,cn=auth ACL
rule allowing root to modify the server configuration. If you need to use
a simple bind to access your server, pass the credentials in I(bind_dn)
and I(bind_pw).
author:
- Jiri Tyr (@jtyr)
requirements:
- python-ldap
options:
attributes:
description:
- If I(state=present), attributes necessary to create an entry. Existing
entries are never modified. To assert specific attribute values on an
existing entry, use M(ldap_attr) module instead.
objectClass:
description:
- If I(state=present), value or list of values to use when creating
the entry. It can either be a string or an actual list of
strings.
params:
description:
- List of options which allows to overwrite any of the task or the
I(attributes) options. To remove an option, set the value of the option
to C(null).
state:
description:
- The target state of the entry.
choices: [present, absent]
default: present
extends_documentation_fragment:
- community.general.ldap.documentation
'''
EXAMPLES = """
- name: Make sure we have a parent entry for users
ldap_entry:
dn: ou=users,dc=example,dc=com
objectClass: organizationalUnit
- name: Make sure we have an admin user
ldap_entry:
dn: cn=admin,dc=example,dc=com
objectClass:
- simpleSecurityObject
- organizationalRole
attributes:
description: An LDAP administrator
userPassword: "{SSHA}tabyipcHzhwESzRaGA7oQ/SDoBZQOGND"
- name: Get rid of an old entry
ldap_entry:
dn: ou=stuff,dc=example,dc=com
state: absent
server_uri: ldap://localhost/
bind_dn: cn=admin,dc=example,dc=com
bind_pw: password
#
# The same as in the previous example but with the authentication details
# stored in the ldap_auth variable:
#
# ldap_auth:
# server_uri: ldap://localhost/
# bind_dn: cn=admin,dc=example,dc=com
# bind_pw: password
- name: Get rid of an old entry
ldap_entry:
dn: ou=stuff,dc=example,dc=com
state: absent
params: "{{ ldap_auth }}"
"""
RETURN = """
# Default return values
"""
import traceback
from ansible.module_utils.basic import AnsibleModule, missing_required_lib
from ansible.module_utils.six import string_types
from ansible.module_utils._text import to_native, to_bytes
from ansible_collections.community.general.plugins.module_utils.ldap import LdapGeneric, gen_specs
LDAP_IMP_ERR = None
try:
import ldap.modlist
HAS_LDAP = True
except ImportError:
LDAP_IMP_ERR = traceback.format_exc()
HAS_LDAP = False
class LdapEntry(LdapGeneric):
def __init__(self, module):
LdapGeneric.__init__(self, module)
# Shortcuts
self.state = self.module.params['state']
# Add the objectClass into the list of attributes
self.module.params['attributes']['objectClass'] = (
self.module.params['objectClass'])
# Load attributes
if self.state == 'present':
self.attrs = self._load_attrs()
def _load_attrs(self):
""" Turn attribute's value to array. """
attrs = {}
for name, value in self.module.params['attributes'].items():
if name not in attrs:
attrs[name] = []
if isinstance(value, list):
attrs[name] = list(map(to_bytes, value))
else:
attrs[name].append(to_bytes(value))
return attrs
def add(self):
""" If self.dn does not exist, returns a callable that will add it. """
def _add():
self.connection.add_s(self.dn, modlist)
if not self._is_entry_present():
modlist = ldap.modlist.addModlist(self.attrs)
action = _add
else:
action = None
return action
def delete(self):
""" If self.dn exists, returns a callable that will delete it. """
def _delete():
self.connection.delete_s(self.dn)
if self._is_entry_present():
action = _delete
else:
action = None
return action
def _is_entry_present(self):
try:
self.connection.search_s(self.dn, ldap.SCOPE_BASE)
except ldap.NO_SUCH_OBJECT:
is_present = False
else:
is_present = True
return is_present
def main():
module = AnsibleModule(
argument_spec=gen_specs(
attributes=dict(default={}, type='dict'),
objectClass=dict(type='raw'),
params=dict(type='dict'),
state=dict(default='present', choices=['present', 'absent']),
),
supports_check_mode=True,
)
if not HAS_LDAP:
module.fail_json(msg=missing_required_lib('python-ldap'),
exception=LDAP_IMP_ERR)
state = module.params['state']
# Check if objectClass is present when needed
if state == 'present' and module.params['objectClass'] is None:
module.fail_json(msg="At least one objectClass must be provided.")
# Check if objectClass is of the correct type
if (
module.params['objectClass'] is not None and not (
isinstance(module.params['objectClass'], string_types) or
isinstance(module.params['objectClass'], list))):
module.fail_json(msg="objectClass must be either a string or a list.")
# Update module parameters with user's parameters if defined
if 'params' in module.params and isinstance(module.params['params'], dict):
for key, val in module.params['params'].items():
if key in module.argument_spec:
module.params[key] = val
else:
module.params['attributes'][key] = val
# Remove the params
module.params.pop('params', None)
# Instantiate the LdapEntry object
ldap = LdapEntry(module)
# Get the action function
if state == 'present':
action = ldap.add()
elif state == 'absent':
action = ldap.delete()
# Perform the action
if action is not None and not module.check_mode:
try:
action()
except Exception as e:
module.fail_json(msg="Entry action failed.", details=to_native(e), exception=traceback.format_exc())
module.exit_json(changed=(action is not None))
if __name__ == '__main__':
main()

View file

@ -0,0 +1,150 @@
#!/usr/bin/python
# -*- coding: utf-8 -*-
# Copyright: (c) 2017-2018, Keller Fuchs <kellerfuchs@hashbang.sh>
# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
from __future__ import absolute_import, division, print_function
__metaclass__ = type
ANSIBLE_METADATA = {
'metadata_version': '1.1',
'status': ['preview'],
'supported_by': 'community'
}
DOCUMENTATION = '''
---
module: ldap_passwd
short_description: Set passwords in LDAP.
description:
- Set a password for an LDAP entry. This module only asserts that
a given password is valid for a given entry. To assert the
existence of an entry, see M(ldap_entry).
notes:
- The default authentication settings will attempt to use a SASL EXTERNAL
bind over a UNIX domain socket. This works well with the default Ubuntu
install for example, which includes a cn=peercred,cn=external,cn=auth ACL
rule allowing root to modify the server configuration. If you need to use
a simple bind to access your server, pass the credentials in I(bind_dn)
and I(bind_pw).
author:
- Keller Fuchs (@KellerFuchs)
requirements:
- python-ldap
options:
passwd:
required: true
description:
- The (plaintext) password to be set for I(dn).
extends_documentation_fragment:
- community.general.ldap.documentation
'''
EXAMPLES = """
- name: Set a password for the admin user
ldap_passwd:
dn: cn=admin,dc=example,dc=com
passwd: "{{ vault_secret }}"
- name: Setting passwords in bulk
ldap_passwd:
dn: "{{ item.key }}"
passwd: "{{ item.value }}"
with_dict:
alice: alice123123
bob: "|30b!"
admin: "{{ vault_secret }}"
"""
RETURN = """
modlist:
description: list of modified parameters
returned: success
type: list
sample: '[[2, "olcRootDN", ["cn=root,dc=example,dc=com"]]]'
"""
import traceback
from ansible.module_utils.basic import AnsibleModule, missing_required_lib
from ansible_collections.community.general.plugins.module_utils.ldap import LdapGeneric, gen_specs
LDAP_IMP_ERR = None
try:
import ldap
HAS_LDAP = True
except ImportError:
LDAP_IMP_ERR = traceback.format_exc()
HAS_LDAP = False
class LdapPasswd(LdapGeneric):
def __init__(self, module):
LdapGeneric.__init__(self, module)
# Shortcuts
self.passwd = self.module.params['passwd']
def passwd_check(self):
try:
tmp_con = ldap.initialize(self.server_uri)
except ldap.LDAPError as e:
self.fail("Cannot initialize LDAP connection", e)
if self.start_tls:
try:
tmp_con.start_tls_s()
except ldap.LDAPError as e:
self.fail("Cannot start TLS.", e)
try:
tmp_con.simple_bind_s(self.dn, self.passwd)
except ldap.INVALID_CREDENTIALS:
return True
except ldap.LDAPError as e:
self.fail("Cannot bind to the server.", e)
else:
return False
finally:
tmp_con.unbind()
def passwd_set(self):
# Exit early if the password is already valid
if not self.passwd_check():
return False
# Change the password (or throw an exception)
try:
self.connection.passwd_s(self.dn, None, self.passwd)
except ldap.LDAPError as e:
self.fail("Unable to set password", e)
# Password successfully changed
return True
def main():
module = AnsibleModule(
argument_spec=gen_specs(passwd=dict(no_log=True)),
supports_check_mode=True,
)
if not HAS_LDAP:
module.fail_json(msg=missing_required_lib('python-ldap'),
exception=LDAP_IMP_ERR)
ldap = LdapPasswd(module)
if module.check_mode:
module.exit_json(changed=ldap.passwd_check())
module.exit_json(changed=ldap.passwd_set())
if __name__ == '__main__':
main()