# -*- coding: utf-8 -*-
# author : s
import random,string
from ldap3 import Server,Connection,ALL,SUBTREE,ALL_ATTRIBUTES,MODIFY_REPLACE,MODIFY_ADD,MODIFY_DELETE
from passlib.hash import ldap_salted_sha1 as ssha
from app.utils import ErrMsg
class LdapOp(object):
"""
Operation Dcouments: http://ldap3.readthedocs.io/
"""
def __init__(self,ip,port,user,passwd):
self._ip = ip
self._port = port
self._user = user
self._passwd = passwd
self.dn = self._user.split(',',1)[1]
self.s = Server(self._ip,self._port,get_info=ALL)
self._conn = Connection(self.s, self._user, self._passwd, auto_bind=True)
@property
def conn(self):
if not self._conn:
print('ldap conn init ')
self._conn = Connection(self.s, self._user, self._passwd, auto_bind=True)
return self._conn
def searchAll(self,name='top'):
entries = self.conn.extend.standard.paged_search(self.dn, '(objectClass=%s)' % name ,attributes=['cn', 'givenName','gidNumber','uidNumber','telephoneNumber','mail'])
en = list(entries)
ulist = [v for v in en if 'People' in v.get('dn','') and 'uid' in v.get('dn','') ]
l = []
for v in ulist:
udict = {}
udict['dn'] = v['dn']
udict['cn'] = v['attributes'].get('cn','')[0] if len(v['attributes'].get('cn','')) > 0 else v['attributes'].get('cn','')
udict['gid'] = str(v['attributes'].get('gidNumber',''))
udict['mail'] = v['attributes'].get('mail','')[0] if len(v['attributes'].get('mail','')) > 0 else v['attributes'].get('mail','')
udict['phone'] = v['attributes'].get('telephoneNumber','')[0] if len(v['attributes'].get('telephoneNumber','')) > 0 else v['attributes'].get('telephoneNumber','')
l.append(udict)
# append user is groups
groups = self.searchGroups()
##
for user in l:
user['groups'] = []
for group in groups:
# group.get('memberUid',[])
if user.get('cn', '') in group.get('memberUid', []):
user['groups'].append(group.get('cn'))
#print(l)
return l
def getGroups(self):
l = []
return l
def user_addGroup(self, group_dn, user_cn=[]):
data = self.conn.modify(group_dn, {'memberuid': [(MODIFY_ADD, user_cn)]})
return self.conn.entries
def user_deleteGroup(self,group_dn,user_cn=[]):
data = self.conn.modify(group_dn, {'memberuid': [(MODIFY_DELETE,user_cn)]})
print(data)
return self.conn.entries
def addGroup(self,args):
ouname = self.get_ouname('(|(ou=Groups)(ou=Group))')
print('ouname=',ouname)
groupname = args.get('name')
groupid = args.get('groupid')
#grouppassword = args.get('grouppassword')
cndn = 'cn=%s,%s' % (groupname,ouname)
print(cndn)
attr = {
'objectClass': ['posixGroup', 'top'],
'cn' : groupname,
'gidNumber': groupid,
#'userPassword': grouppassword
}
sgroup = [ g for g in self.searchGroups() if g.get('cn','') == groupname or g.get('gidNumber','') == groupid ]
if sgroup:
return {'msg': 'err', 'data': u' ID , !'}
try:
data = self.conn.add(cndn, attributes=attr)
msg = 'ok'
except Exception as e:
data = e
msg = 'err'
finally:
#self.conn.unbind()
return {'msg': msg , 'data': data}
def searchGroups(self,groupname=''):
if groupname:
#print(self.conn)
rv = self.conn.search('%s' % self.dn, '( &(objectClass=posixGroup)(cn=%s))' %groupname,
attributes=['sn', 'cn', 'objectclass', 'userPassword', 'gidNumber','memberUid'])
else:
rv = self.conn.search('%s' % self.dn, '(objectClass=posixGroup)',
attributes=['sn', 'cn', 'objectclass', 'userPassword', 'gidNumber','memberUid'])
data = []
if rv:
for en in self.conn.entries:
endict = en.entry_get_attributes_dict()
suben = {
'cn': str(en['cn'][0]),
'gidNumber': str(en['gidNumber'][0]),
#'objectClass': ','.join(en['objectClass']),
#'userPassword': en['userPassword'][0],
'dn': str(en.entry_get_dn()),
'memberUid': endict.get('memberUid',[]),
}
data.append(suben)
return data
def deleteGroup(self,name=''):
if not name:
return {'msg':'err','data': 'Group Name not is None'}
group = self.searchGroups(name)
if len(group)== 1:
try:
self.conn.delete(group[0]['dn'])
rv = {'msg':'ok','data':''}
except Exception as e:
rv = {'msg': 'err','data': e}
elif len(group) == 0 :
rv = {'msg': 'err', 'data': 'Not group Find'}
else:
rv = {'msg': 'err', 'data': 'Find %d groups '} %len(group)
return rv
def addUser(self,args):
cndn = 'uid=%s,ou=People,%s' % ( args.get('name'),self.dn)
#object_class = [ 'account','posixAccount', 'top', 'shadowAccount']
if args.get('mail',''):
mail = args.get('mail')
else:
if self.dn == 'dc=test,dc=com':
dn = 'test.com'
mail = '%s@%s' % (args.get('name'), dn)
else:
dn ='.'.join(map(lambda x: x[3:],self.dn.split(',')))
mail = '%s@%s' % (args.get('name'),dn)
attr = {
'objectClass': ['account', 'posixAccount', 'top', 'shadowAccount'],
'userPassword': args.get('passwd'),
'uid': args.get('name'),
'cn': args.get('name'),
'shadowLastChange': '17038',
'shadowMax': '99999',
'shadowWarning': '7',
'uidNumber': args.get('phonenumber'),
'gidNumber': args.get('groupid'),
'homeDirectory': '/home/%s' % args.get('name'),
'mail': mail,
'telephoneNumber': args.get('phonenumber'),
'displayname': args.get('name'),
}
#print('*' *100)
#print(cndn)
#print(attr)
try:
data = self.conn.add(cndn, attributes=attr)
if not data:
attr['objectClass'] = ['posixAccount', 'shadowAccount', 'top', 'person', 'organizationalPerson','inetOrgPerson']
attr['sn'] = args.get('name')
data = self.conn.add(cndn, attributes=attr)
if not data:
msg = self.conn.result['message']
raise ValueError(msg)
msg = 'ok'
except Exception as e:
data = e
msg = 'err'
finally:
self.conn.unbind()
return {'msg': msg , 'data': data}
def deleteUser(self,name=''):
if not name:
return {'msg':'err','data': 'Name not is None'}
if 'dc' in name:
dn = name
else:
dn = 'uid=%s,ou=People,%s' %(name,self.dn)
print(dn)
try:
self.conn.delete(dn)
rv = {'msg':'ok','data':''}
except Exception as e:
rv = {'msg': 'err','data': e}
finally:
self.conn.unbind()
return rv
def searchUser(self,name):
try:
users = self.searchAll()
if name:
data = [ user for user in users if name in user.get('cn') ]
else:
data = users
rv = 'ok'
except Exception as e:
data = e
rv = 'err'
finally:
return {'msg':rv,'data':data}
def searchSinUser(self,name):
try:
ga = self.conn.extend.standard.paged_search(search_base=self.dn,
search_filter='(uid=%s)' %name,
search_scope= SUBTREE,
attributes=ALL_ATTRIBUTES)
user = list(ga)
if user:
data = user[0].get('attributes')
d = {
'user': str(data.get('cn')[0]),
'passwd': data.get('userPassword')[0].decode('utf-8'),
'gid': data.get('gidNumber'),
'mail': data.get('mail')[0],
'phonenumber': data.get('uidNumber')
}
else:
d = {}
users = self.searchAll()
usingle = [d for d in users if d.get('cn') == name ]
u = {}
if usingle:
u = usingle[0]
except Exception as e:
print(e)
u = {'msg': ErrMsg()}
finally:
#print('user=',u)
x = u.update(d)
print('u=',u)
return u
def editUser(self,args):
try:
cn = 'uid=%s,ou=People,%s' % (args.get('user'), self.dn)
print(cn)
passwd = args.get('passwd','')
user = self.searchSinUser(args.get('user'))
data = ''
if user.get('passwd') != passwd:
if 'SSHA' not in passwd:
passwd = self.encodePasswd(passwd)
data = self.conn.modify(cn, {'userPassword': (MODIFY_REPLACE,passwd)})
if user.get('gid') != args.get('gid') and args.get('gid') != 'default':
data = self.conn.modify(cn,{'gidNumber': (MODIFY_REPLACE,args.get('gid')) })
except Exception as e:
ErrMsg()
data = e
finally:
print('data', data)
return data
def setPasswd(self,**kwargs):
try:
cn = 'uid=%s,ou=People,%s' % (kwargs.get('user',''), self.dn)
data = self.conn.modify(cn,{'userPassword':(MODIFY_REPLACE,kwargs.get('passwd', ''))})
except Exception as e:
data = ErrMsg()
finally:
return data
@staticmethod
def GenPasswd():
return ''.join(random.sample(string.ascii_letters + string.digits, 8))
def _searchUser_org(self,username):
print('in-search-org')
ga = self.conn.extend.standard.paged_search(search_base=self.dn,
search_filter='(uid=%s)' %username,
search_scope= SUBTREE,
attributes=ALL_ATTRIBUTES)
user = list(ga)
print(user)
entry = self.conn.response[0]
dn = entry['dn']
attr_dict = entry['attributes']
return (dn,attr_dict)
def authUser(self,username,password):
try:
cn = 'uid=%s,ou=People,%s' % (username,self.dn)
conn2 = Connection(self._ip, user=cn, password=password,
check_names=True, lazy=False, raise_exceptions=False)
conn2.bind()
if conn2.result["description"] == "success":
rv = 'ok'
data = ' '
else:
rv = 'err'
data = ' , !'
except Exception as e:
rv = 'err'
data = ErrMsg()
finally:
return {'rv': rv,'data':data}
@staticmethod
def encodePasswd(password=''):
"""
:param password:
:return:
"""
if password:
return ssha.encrypt(password,salt_size=12)
return ''
def get_ouname(self,ouname):
"""
ouname = '(|(ou=Groups)(ou=Group))'
:param ouname:
:return:
"""
print(self.dn,ouname)
ou = self.conn.search('%s' % self.dn, '%s' % ouname )
print(ou)
retry = self.conn.entries
num = len(retry)
if num == 0:
return []
else:
return retry[0].entry_get_dn()