# # Copyright(C) 2005 INL # Written by Jean Gillaux <jean@inl.fr> # # This program is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation, version 3 of the License. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program; if not, see <http://www.gnu.org/licenses/>. # # """LDAP related stuff for nupyf. This is a set to handle ldap operations for nupyf: - connection - mapping of rules to ldap NuAccessControlList object definition - sync of ldap acls with rules from xml """ __version__ = '0.2' __author__ = 'Jean Gillaux' import ldap from ldap.modlist import addModlist import nubackend USE_IPV6 = False ATTR_TYPE_MULTIPLE = nubackend.ATTR_TYPE_MULTIPLE ATTR_TYPE_SIMPLE= nubackend.ATTR_TYPE_SIMPLE | set(['cn','objectClass']) ALL_ATTR=(ATTR_TYPE_MULTIPLE | ATTR_TYPE_SIMPLE) class LDAPConn(object): """Handles connection to ldap server, and store information relative to the connection. Example: conn = LDAPConn('ldap.company','cn=admin, dc=company, dc=com','secret','ou=acls, dc=company, dc=com') basedn is the basedn for nufw acces control lists. """ def __init__(self, host, who, cred, basedn, port=''): self.host = host self.port = port self.basedn = basedn if self.port: self.conn = ldap.open(self.host, port = self.port) else: self.conn = ldap.open(self.host) self.conn.simple_bind_s(who, cred) class LDAPTool(object): """Handles search, add and delete operations on a ldap tree. """ def __init__(self, conn, basedn=''): self._c = conn self._basedn = conn.basedn if basedn: self._basedn = basedn def search(self): r = self._c.conn.search(self._basedn, ldap.SCOPE_SUBTREE, '(objectClass=NuAccessControlList)') while 1: result_type, result_data = self._c.conn.result(r, 0) if result_data == []: break else: yield LDAPRule(ldapresult=result_data) def add(self, ldaprule): """Add an object in the ldap tree. the dn is made with "cn" atrribute of ldaprule and basedn """ h = ldaprule.attrs() dn = 'cn='+ldaprule['cn'][0]+','+self._basedn modlist = addModlist(h) self._c.conn.add_s(dn, modlist) def delete(self, ldaprule): """Delete an object from the ldap tree. ldaprule is an LDAPRule object """ dn = 'cn='+ldaprule['cn'][0]+','+self._basedn self._c.conn.delete_s(dn) class LDAPRule(nubackend.NURule): def __init__(self, xmlrule=None, ldapresult=None): super(LDAPRule, self).__init__(xmlrule, ATTR_TYPE_SIMPLE, ATTR_TYPE_MULTIPLE, ALL_ATTR - set(['cn'])) self.h['objectClass'] = set(['top','NuAccessControlList']) self.h['cn'] = set(['']) if xmlrule is not None: self['cn'] = "acl%s_rule%s" % (xmlrule.aclid, xmlrule.cpt) if ldapresult: ldaph = ldapresult[0][1] for k, v in ldaph.iteritems(): if k in self.attr_type_simple: self.h[k] = set(v) if k in self.attr_type_multiple: self.h[k] = set(v) def attrs(self): res={} for k, v in self.h.iteritems(): v = list(v) if USE_IPV6 and k in ('SrcIPStart', 'SrcIPEnd', 'DstIPStart', 'DstIPEnd'): # Convert IPv4 to IPv6 ip = int(v[0]) ip = str(0xffff00000000 + ip) res[k] = [ip] else: res[k] = v return res class LDAPfw(nubackend.NUBackend): """This class inserts/removes rules into ldap tree. It's ldap nufw backend. """ def __init__(self, fw): super(LDAPfw, self).__init__(fw=fw, backend_class=LDAPRule) self.backend_class = LDAPRule def process(self, conn): """This method takes rules from xml and ldap, then merge them into ldap tree. - if a rule from ldap is not in the xml rules, it is deleted from the ldap tree. - if a rule from xml is not in the ldap rules, it is inserted in the ldap tree. """ tool = LDAPTool(conn) for rldap in tool.search(): tool.delete(rldap) for rxml in self.rules: tool.add(rxml)