#-*- coding: utf-8 -*- # Copyright 2008-2010 Calculate Ltd. http://www.calculate-linux.org # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. import ldap from cl_utils import _error class ldapFun(_error): '''Объект для работы с LDAP сервером подключение к серверу и поиск данных ''' def __init__(self, dnUser, password, host="localhost"): self.conLdap = False # Получаем соединение с LDAP try: self.conLdap = self.__ldapConnect(dnUser, password, host) except ldap.LDAPError, e: self.setError(e[0]['desc']) def __ldapConnect(self, dnUser, password, host): """Соединение с LDAP сервером""" conLdap = ldap.initialize('ldap://%s'%host) conLdap.simple_bind_s(dnUser, password) return conLdap def ldapSearch(self,baseDN, searchScope, searchFilter, retrieveAttributes): try: ldap_result_id = self.conLdap.search(baseDN, searchScope, searchFilter, retrieveAttributes) result_set = [] while 1: result_type, result_data = self.conLdap.result(ldap_result_id, 0) if (result_data == []): break else: if result_type == ldap.RES_SEARCH_ENTRY: result_set.append(result_data) except ldap.NO_SUCH_OBJECT: return [] except: return False return result_set class ldapUser(_error): """Получение данных для пользователя из LDAP""" # Данные из /etc/ldap.conf _dictData = {} # Объект LDAP ldapObj = False # Подключение к LDAP conLdap = False def getDataInLdapConf(self, bindData=True, cache=True): """Получение данных из /etc/ldap.conf""" data = [("host",'host'), ("usersDN",'nss_base_passwd'), ("groupsDN",'nss_base_group')] if bindData: data += [("bindDn",'binddn'), ("bindPw",'bindpw')] namesData = map(lambda x: x[0], data) # Данные из кеша, если он есть if cache and self._dictData and\ set(namesData)<=set(self._dictData.keys()): return self._dictData fileName = "/etc/ldap.conf" getStrList = lambda x: reduce(lambda x,y: [x,y.upper()],([x]*2)) workData = map(lambda x: (x[0],getStrList(x[1]),len(x[1])), data) dictData = {} splList = (" ", "\t") try: for line in open(fileName): for name, keys, lenKey in workData: if not name in dictData.keys() and\ filter(lambda x: line.startswith(x), keys) and\ len(line)>lenKey: spl = line[lenKey] if spl in splList: if not name in dictData: dictData[name] = [] if name in ("usersDN", "groupsDN"): dictData[name].append(line.rpartition(spl)[2].\ partition('?')[0].strip()) else: dictData[name].append(line.rpartition(spl)[2].\ strip()) except: self.setError(_("Can not open %s")%fileName) return False if set(dictData.keys()) == set(namesData): # Кеширование данных if cache: self._dictData.clear() self._dictData.update(dictData) return dictData else: return {} def getBindConnectData(self): """Получение данных для соединения с LDAP bind пользователем""" configdata = self.getDataInLdapConf() if configdata: bindDn = configdata["bindDn"][0] bindPw = configdata["bindPw"][0] host = configdata["host"][0] return bindDn, bindPw, host return False def getUsersDN(self): """Получение DN пользователей""" configdata = self.getDataInLdapConf(bindData=False) if configdata: usersDN = self._dictData["usersDN"][0] return usersDN return False def getHost(self): """Получение LDAP хоста""" configdata = self.getDataInLdapConf(bindData=False) if configdata: host = configdata["host"][0] return host return False def getGroupsDN(self): """Получение списка DN групп""" configdata = self.getDataInLdapConf(bindData=False) if configdata: groupsDNs = self._dictData["groupsDN"] return groupsDNs return False def getUserLdapInfo(self, userName): """Выдаем информацию о пользователе из LDAP""" connectData = self.getBindConnectData() if not connectData: return {} bindDn, bindPw, host = connectData usersDN = self.getUsersDN() groupsDNs = self.getGroupsDN() # Соединяемся с LDAP if not self.ldapConnect(bindDn, bindPw, host): return False searchUser = self.ldapObj.ldapSearch(usersDN, ldap.SCOPE_ONELEVEL, "uid=%s" %userName, None) if not searchUser: return False uid = False gid = False fullName = "" mail = "" jid = "" group = "" if 'uidNumber' in searchUser[0][0][1]: uid = searchUser[0][0][1]['uidNumber'][0] if 'gidNumber' in searchUser[0][0][1]: gid = searchUser[0][0][1]['gidNumber'][0] for groupDN in groupsDNs: searchGroup = self.ldapObj.ldapSearch(groupDN, ldap.SCOPE_ONELEVEL, "gidNumber=%s" %gid, ['cn']) if searchGroup: group = searchGroup[0][0][1]['cn'][0] break if 'cn' in searchUser[0][0][1]: fullName = searchUser[0][0][1]['cn'][0] if 'mail' in searchUser[0][0][1]: mail = searchUser[0][0][1]['mail'][0] if 'registeredAddress' in searchUser[0][0][1]: jid = searchUser[0][0][1]['registeredAddress'][0] if 'homeDirectory' in searchUser[0][0][1]: home = searchUser[0][0][1]['homeDirectory'][0] if uid and gid: return {"uid":uid, "gid":gid, "fullName":fullName, "mail":mail, "jid":jid, "home":home, "group":group} else: return {} def ldapConnect(self, bindDn, bindPw, host): """Подключение к LDAP""" if not self.ldapObj: ldapObj = ldapFun(bindDn, bindPw, host) if ldapObj.getError(): return False # Устанавливаем у объекта соединение и объект LDAP функций self.ldapObj = ldapObj self.conLdap = ldapObj.conLdap return True