Files @ d1a4cfa37a3f
Branch filter:

Location: majic-ansible-roles/roles/ldap_server/library/ldap_permissions - annotation

branko
MAR-1: Added a small module for managing the LDAP permissions.
d1a4cfa37a3f
d1a4cfa37a3f
d1a4cfa37a3f
d1a4cfa37a3f
d1a4cfa37a3f
d1a4cfa37a3f
d1a4cfa37a3f
d1a4cfa37a3f
d1a4cfa37a3f
d1a4cfa37a3f
d1a4cfa37a3f
d1a4cfa37a3f
d1a4cfa37a3f
d1a4cfa37a3f
d1a4cfa37a3f
d1a4cfa37a3f
d1a4cfa37a3f
d1a4cfa37a3f
d1a4cfa37a3f
d1a4cfa37a3f
d1a4cfa37a3f
d1a4cfa37a3f
d1a4cfa37a3f
d1a4cfa37a3f
d1a4cfa37a3f
d1a4cfa37a3f
d1a4cfa37a3f
d1a4cfa37a3f
d1a4cfa37a3f
d1a4cfa37a3f
d1a4cfa37a3f
d1a4cfa37a3f
d1a4cfa37a3f
d1a4cfa37a3f
d1a4cfa37a3f
d1a4cfa37a3f
d1a4cfa37a3f
d1a4cfa37a3f
d1a4cfa37a3f
d1a4cfa37a3f
d1a4cfa37a3f
d1a4cfa37a3f
d1a4cfa37a3f
d1a4cfa37a3f
d1a4cfa37a3f
d1a4cfa37a3f
d1a4cfa37a3f
d1a4cfa37a3f
d1a4cfa37a3f
d1a4cfa37a3f
d1a4cfa37a3f
d1a4cfa37a3f
d1a4cfa37a3f
d1a4cfa37a3f
d1a4cfa37a3f
d1a4cfa37a3f
d1a4cfa37a3f
d1a4cfa37a3f
d1a4cfa37a3f
d1a4cfa37a3f
d1a4cfa37a3f
d1a4cfa37a3f
d1a4cfa37a3f
d1a4cfa37a3f
d1a4cfa37a3f
d1a4cfa37a3f
d1a4cfa37a3f
d1a4cfa37a3f
d1a4cfa37a3f
d1a4cfa37a3f
d1a4cfa37a3f
d1a4cfa37a3f
d1a4cfa37a3f
d1a4cfa37a3f
d1a4cfa37a3f
d1a4cfa37a3f
d1a4cfa37a3f
d1a4cfa37a3f
d1a4cfa37a3f
d1a4cfa37a3f
d1a4cfa37a3f
d1a4cfa37a3f
d1a4cfa37a3f
d1a4cfa37a3f
d1a4cfa37a3f
d1a4cfa37a3f
d1a4cfa37a3f
d1a4cfa37a3f
d1a4cfa37a3f
d1a4cfa37a3f
d1a4cfa37a3f
d1a4cfa37a3f
d1a4cfa37a3f
d1a4cfa37a3f
d1a4cfa37a3f
d1a4cfa37a3f
d1a4cfa37a3f
d1a4cfa37a3f
d1a4cfa37a3f
d1a4cfa37a3f
d1a4cfa37a3f
d1a4cfa37a3f
d1a4cfa37a3f
d1a4cfa37a3f
d1a4cfa37a3f
d1a4cfa37a3f
d1a4cfa37a3f
d1a4cfa37a3f
d1a4cfa37a3f
d1a4cfa37a3f
d1a4cfa37a3f
d1a4cfa37a3f
d1a4cfa37a3f
d1a4cfa37a3f
d1a4cfa37a3f
d1a4cfa37a3f
d1a4cfa37a3f
d1a4cfa37a3f
d1a4cfa37a3f
d1a4cfa37a3f
d1a4cfa37a3f
d1a4cfa37a3f
d1a4cfa37a3f
d1a4cfa37a3f
d1a4cfa37a3f
d1a4cfa37a3f
d1a4cfa37a3f
d1a4cfa37a3f
d1a4cfa37a3f
d1a4cfa37a3f
d1a4cfa37a3f
d1a4cfa37a3f
d1a4cfa37a3f
d1a4cfa37a3f
d1a4cfa37a3f
d1a4cfa37a3f
d1a4cfa37a3f
d1a4cfa37a3f
d1a4cfa37a3f
d1a4cfa37a3f
d1a4cfa37a3f
d1a4cfa37a3f
d1a4cfa37a3f
d1a4cfa37a3f
d1a4cfa37a3f
d1a4cfa37a3f
d1a4cfa37a3f
d1a4cfa37a3f
d1a4cfa37a3f
d1a4cfa37a3f
d1a4cfa37a3f
d1a4cfa37a3f
d1a4cfa37a3f
d1a4cfa37a3f
d1a4cfa37a3f
d1a4cfa37a3f
d1a4cfa37a3f
d1a4cfa37a3f
d1a4cfa37a3f
d1a4cfa37a3f
d1a4cfa37a3f
d1a4cfa37a3f
d1a4cfa37a3f
d1a4cfa37a3f
d1a4cfa37a3f
d1a4cfa37a3f
d1a4cfa37a3f
d1a4cfa37a3f
d1a4cfa37a3f
d1a4cfa37a3f
d1a4cfa37a3f
d1a4cfa37a3f
d1a4cfa37a3f
d1a4cfa37a3f
d1a4cfa37a3f
d1a4cfa37a3f
d1a4cfa37a3f
d1a4cfa37a3f
d1a4cfa37a3f
d1a4cfa37a3f
d1a4cfa37a3f
d1a4cfa37a3f
d1a4cfa37a3f
d1a4cfa37a3f
d1a4cfa37a3f
d1a4cfa37a3f
d1a4cfa37a3f
d1a4cfa37a3f
d1a4cfa37a3f
d1a4cfa37a3f
d1a4cfa37a3f
d1a4cfa37a3f
d1a4cfa37a3f
d1a4cfa37a3f
d1a4cfa37a3f
d1a4cfa37a3f
d1a4cfa37a3f
d1a4cfa37a3f
d1a4cfa37a3f
d1a4cfa37a3f
d1a4cfa37a3f
d1a4cfa37a3f
#!/usr/bin/env python

DOCUMENTATION = """
---
module: ldap_permissions
short_description: Sets permissions/ACL for LDAP database.
description:
  - Sets permissions (access control list) for LDAP database.
version_added: 1.7.2
author: Branko Majic
notes:
  - Requires the python-ldap Python package on remote host. For Debian and
    derivatives, this is as easy as apt-get install python-ldap.
requirements:
  - python-ldap
options:
  filter:
    description:
      - LDAP filter that should be used for locating the database on which the
        ACL rules should be applied. This filter will be used for search under
        the C(cn=config) base DN. For regular user databases, the filter should
        probably be based on the C(olcSuffix) attribute. The filter must result
        in a unique entry.
    required: true
    default: ""
  rules:
    description:
      - LDAP rules that should be applied to the LDAP database. The rules should
        be provided as a list of strings. Each string should be an access rule
        as described in OpenLDAP administrator guide at
        U(http://www.openldap.org/doc/admin24/access-control.html). Use long
        format for specifying this parameter (see examples below).
    required: true
    default: ""
"""

EXAMPLES = """
# Set-up of rules for regular database.
ldap_permissions:
  - filter: '(olcSuffix=dc=example,dc=com)'
    rules:
      - >
        to *
        by dn.exact=gidNumber=0+uidNumber=0,cn=peercred,cn=external,cn=auth manage
        by * break
      - >
        to attrs=userPassword,shadowLastChange
        by self write
        by anonymous auth
        by dn="cn=admin,dc=example,dc=com" write
        by * none
      - >
        to dn.base=""
        by * read
      - >
        to *
        by self write
        by dn="cn=admin,dc=example,dc=com" write
        by * none
# Set-up rules for a configuration database. This time with a single rule in a
# single line.
ldap_permissions:
  - filter: '(olcDatabase={0}config)'
    rules:
      - to * by dn.exact=gidNumber=0+uidNumber=0,cn=peercred,cn=external,cn=auth manage by * break
"""

# Try to load the Python LDAP module.
try:
    import ldap
    import ldap.sasl
    import ldap.modlist
except ImportError:
    ldap_found = False
else:
    ldap_found = True


class LDAPPermissions(object):
    """
    This class encapsulates functionality for applying ACL to an LDAP database.
    """

    def __init__(self, module):
        """
        Initialises class instance. Reads parameters from the passed
        AnsibleModule instance, and connects to the LDAP server.
        """

        self.module = module
        self.filter = module.params["filter"]
        self.rules = module.params["rules"]
        self._connect()

    def _connect(self):
        """
        Initialises LDAP connection and binds to the LDAP server.

        Binding is done using the SASL EXTERNAL mechanism.

        Returns:

        Nothing.
        """

        self.connection = ldap.initialize("ldapi:///")
        self.connection.sasl_interactive_bind_s("", ldap.sasl.external())

    def _get_database(self):
        """
        Retrieves the requested database entry.

        Returns:

        Database entry. Return format is same as for function ldap.search_s.
        """

        return self.connection.search_s(base="cn=config", scope=ldap.SCOPE_ONELEVEL, filterstr=self.filter)

    def _get_modifications(self, database):
        """
        Returns modification list for updatingn the current ACL with requested
        ACL.

        Returns:

        Modification list. The format is suitable for use with functions
        ldap.modify() and ldap.modify_s(). An empty list will be returned if no
        changes are necessary.
        """

        # Fetch the list of current rules.
        current_rules = database[1]["olcAccess"]

        # Set-up list of requested rules.
        requested_rules = []
        for n, rule in enumerate(self.rules):
            rule = "{%d}%s" % (n, rule)
            requested_rules.append(rule.rstrip().lstrip().decode("utf-8").encode("utf-8"))

        return ldap.modlist.modifyModlist({'olcAccess': current_rules}, {'olcAccess': requested_rules})

    def apply(self):
        """
        Applies permissions requested via the Ansible module configuration.

        The function also produces the necessary JSON output, and terminates
        module execution as appropriate.

        Returns:

        Nothing.
        """

        # Fetch the database config based on filter and verify and only one was
        # returned.
        databases = self._get_database()

        if databases == []:
            self.module.fail_json(msg="No database matched filter: %s" % self.filter)
        elif len(databases) > 1:
            self.module.fail_json(msg="More than one databases matched filter: %s" % self.filter)

        database = databases[0]

        # Set-up the modification list.
        modify_list = self._get_modifications(database)

        # Apply modifications if necessary.
        if modify_list == []:
            self.module.exit_json(changed=False)
        else:
            try:
                self.connection.modify_s(database[0], modify_list)
            except ldap.OTHER as e:
                self.module.fail_json(msg="Failed to modify permissions. Rule syntax was possibly incorrect. LDAP server responded: %s" % e)
            self.module.exit_json(changed=True)


def main():
    """
    Runs the module.
    """

    # Construct the module helper for parsing the arguments.
    module = AnsibleModule(
        argument_spec=dict(
            filter=dict(required=True),
            rules=dict(required=True),
            )
        )

    if not ldap_found:
        module.fail_json(msg="The Python LDAP module is required")

    ldap_rules = LDAPPermissions(module)

    ldap_rules.apply()

# Import module snippets.
from ansible.module_utils.basic import *
main()