#-*- 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(_("Failed to 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, shadowAttr=False): """Выдаем информацию о пользователе из 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 convertDict = {'uid':('user','uidNumber'), 'gid':('user','gidNumber'), 'fullName':('user','cn'), 'mail':('user','mail'), 'jid':('user','registeredAddress'), 'home':('user','homeDirectory'), 'group':('group','cn')} if shadowAttr: convertDict.update({'loginShell':('user','loginShell'), 'shadowLastChange':('user','shadowLastChange'), 'shadowMin':('user','shadowMin'), 'shadowMax':('user','shadowMax'), 'shadowWarning':('user','shadowWarning'), 'shadowExpire':('user','shadowExpire'), 'shadowFlag':('user','shadowFlag'), 'groups':('group','memberUid')}) listUserAttr = map(lambda x: x[0], filter(lambda x: x[1][0]=="user", convertDict.items())) listGroupAttr = map(lambda x: x[0], filter(lambda x: x[1][0]=="group", convertDict.items())) uid = "" gid = "" dictOut = {} for dictAttr in listUserAttr: ldapAttr = convertDict[dictAttr][1] if ldapAttr in searchUser[0][0][1]: dictOut[dictAttr] = searchUser[0][0][1][ldapAttr][0] else: dictOut[dictAttr] = "" if dictAttr == 'uid': uid = dictOut[dictAttr] if dictAttr == 'gid': gid = dictOut[dictAttr] if gid: for dictAttr in listGroupAttr: searchGroup = [] ldapAttr = convertDict[dictAttr][1] if dictAttr == "group": for groupDN in groupsDNs: searchGroup = self.ldapObj.ldapSearch(groupDN, ldap.SCOPE_ONELEVEL, "gidNumber=%s" %gid, None) if searchGroup: break if searchGroup: if ldapAttr in searchGroup[0][0][1]: dictOut[dictAttr]=searchGroup[0][0][1][ldapAttr][0] else: dictOut[dictAttr] = "" else: dictOut[dictAttr] = "" elif dictAttr == "groups": userGroupsData = [] for groupDN in groupsDNs: searchGroup = self.ldapObj.ldapSearch(groupDN, ldap.SCOPE_ONELEVEL, "%s=%s" %(ldapAttr,userName), ["cn","gidNumber"]) if searchGroup: userGroupsData += map(lambda x: (x[0][1]["cn"][0], x[0][1]["gidNumber"][0]), searchGroup) dictOut[dictAttr] = userGroupsData if uid and gid: return dictOut 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