Files
@ d1a4cfa37a3f
Branch filter:
Location: majic-ansible-roles/roles/ldap_server/library/ldap_permissions
d1a4cfa37a3f
5.8 KiB
text/plain
MAR-1: Added a small module for managing the LDAP permissions.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 | #!/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()
|