|
|
@ -2,21 +2,27 @@ |
|
|
|
import ldap3 |
|
|
|
import utils |
|
|
|
import config |
|
|
|
import time |
|
|
|
|
|
|
|
def check_result(conn): |
|
|
|
if conn.result['result'] != 0: #see https://www.ietf.org/rfc/rfc4511.txt 4.1.9 |
|
|
|
raise RuntimeError(str(conn.result)) |
|
|
|
|
|
|
|
def connection_decorator(f): |
|
|
|
with ldap3.Connection(config.SERVER, auto_bind=True) as conn: |
|
|
|
with ldap3.Connection(config.SERVER, auto_bind=True, client_strategy=ldap3.STRATEGY_SYNC_RESTARTABLE) as conn: |
|
|
|
def wrapped_f(*args, **kwargs): |
|
|
|
return f(args[0], conn, *args[1:], **kwargs) |
|
|
|
return wrapped_f |
|
|
|
|
|
|
|
def admin_connection_decorator(f): |
|
|
|
with ldap3.Connection(config.SERVER, user=config.ADMIN_CN, password=config.ADMIN_PASSWORD, auto_bind=True) as conn: |
|
|
|
with ldap3.Connection(config.SERVER, user=config.ADMIN_CN, password=config.ADMIN_PASSWORD, auto_bind=True, client_strategy=ldap3.STRATEGY_SYNC_RESTARTABLE) as conn: |
|
|
|
def wrapped_f(*args, **kwargs): |
|
|
|
return f(args[0], conn, *args[1:], **kwargs) |
|
|
|
return wrapped_f |
|
|
|
|
|
|
|
class LILiK_USER(object): |
|
|
|
_attributes = {'uid': [], 'cn': ['givenName']} |
|
|
|
_attributes = ['cn'] |
|
|
|
_read_only_attributes = ['uid'] |
|
|
|
_flags = {'mail': 'accountActive'} |
|
|
|
_hosts = ['ltsp', |
|
|
|
'users'] |
|
|
@ -30,12 +36,12 @@ class LILiK_USER(object): |
|
|
|
_posix_groups = ['users_sites'] |
|
|
|
def __init__(self, entry, posix_groups): |
|
|
|
results = {} |
|
|
|
for attribute in self._attributes.keys(): |
|
|
|
for attribute in self._attributes + self._read_only_attributes: |
|
|
|
self.__setattr__(attribute, str(entry.__getattr__(attribute))) |
|
|
|
services = {} |
|
|
|
|
|
|
|
for service, flag in self._flags.items(): |
|
|
|
services[service] = flag in entry and bool(entry[flag]) |
|
|
|
services[service] = flag in entry and str(entry[flag]) == 'TRUE' |
|
|
|
for host in self._hosts: |
|
|
|
services[host] = 'host' in entry and host in entry['host'] |
|
|
|
for group in self._groups: |
|
|
@ -63,7 +69,7 @@ class LILiK_USER(object): |
|
|
|
for service_changed in services_diff.changed(): |
|
|
|
if service_changed in self._flags: |
|
|
|
flag = self._flags[service_changed] |
|
|
|
modifiers[user_cn][flag] = [(ldap3.MODIFY_REPLACE, [new_lilik_user['services'][service_changed]])] |
|
|
|
modifiers[user_cn][flag] = [(ldap3.MODIFY_REPLACE, [str(new_lilik_user['services'][service_changed]).upper()])] |
|
|
|
|
|
|
|
elif service_changed in self._hosts: |
|
|
|
action = ldap3.MODIFY_ADD if new_lilik_user['services'][service_changed] else ldap3.MODIFY_DELETE |
|
|
@ -79,14 +85,19 @@ class LILiK_USER(object): |
|
|
|
action = ldap3.MODIFY_ADD if new_lilik_user['services'][service_changed] else ldap3.MODIFY_DELETE |
|
|
|
modifiers[group_cn] = {'memberUid': [(action, [self.uid])]} |
|
|
|
else: |
|
|
|
raise Exception('Unknown user attribute') |
|
|
|
else: |
|
|
|
for alias in self._attributes[changed]: |
|
|
|
modifiers[user_cn][alias] = [(ldap3.MODIFY_REPLACE, [new_lilik_user[changed]])] |
|
|
|
raise NameError('Unknown user attribute: %s'%service_changed) |
|
|
|
elif changed in self._attributes: |
|
|
|
if changed == 'cn': |
|
|
|
firstname, surname = new_lilik_user[changed].rsplit(' ', 1) |
|
|
|
modifiers[user_cn]['sn'] = [(ldap3.MODIFY_REPLACE, [surname])] |
|
|
|
modifiers[user_cn]['givenname'] = [(ldap3.MODIFY_REPLACE, [firstname])] |
|
|
|
modifiers[user_cn][changed] = [(ldap3.MODIFY_REPLACE, [new_lilik_user[changed]])] |
|
|
|
for entry_cn, modifier in modifiers.items(): |
|
|
|
if modifier: |
|
|
|
print(entry_cn, modifier) |
|
|
|
conn.modify(entry_cn, modifier) |
|
|
|
check_result(conn) |
|
|
|
print(conn.result) |
|
|
|
if conn.result['result'] != 0: |
|
|
|
return False |
|
|
|
return True |
|
|
@ -98,24 +109,77 @@ class LILiK_LDAP(object): |
|
|
|
c = ldap3.Connection(config.SERVER, user=bind_dn, password=password) |
|
|
|
return c.bind() |
|
|
|
|
|
|
|
@connection_decorator |
|
|
|
@admin_connection_decorator |
|
|
|
def get_users(self, conn): |
|
|
|
conn.search(utils.ldap_path(config.PEOPLE, config.DOMAIN), '(objectclass=posixAccount)', attributes=['uid']) |
|
|
|
check_result(conn) |
|
|
|
return [str(a.uid) for a in conn.entries] |
|
|
|
|
|
|
|
@connection_decorator |
|
|
|
@admin_connection_decorator |
|
|
|
def get_user(self, conn, user_name): |
|
|
|
conn.search(utils.ldap_path(config.PEOPLE, config.DOMAIN), '(&(objectclass=posixAccount)(uid=%s))'%utils.clean_user_name(user_name), attributes=['*', 'memberOf']) |
|
|
|
# return clean_user_name(user_name) |
|
|
|
check_result(conn) |
|
|
|
if len(conn.entries) == 0: |
|
|
|
return None |
|
|
|
raise IndexError("no user found for %s"%user_name) |
|
|
|
entry = conn.entries[0] |
|
|
|
return LILiK_USER(entry, self.get_posix_groups()) |
|
|
|
|
|
|
|
@connection_decorator |
|
|
|
def get_max_uidnumber(self, conn): |
|
|
|
conn.search(utils.ldap_path(config.PEOPLE, config.DOMAIN), |
|
|
|
"(objectClass=posixAccount)", |
|
|
|
attributes=['uidnumber']) |
|
|
|
check_result(conn) |
|
|
|
max = 0 |
|
|
|
for entry in conn.response: |
|
|
|
max = int(entry['attributes']['uidnumber'][0]) if int(entry['attributes']['uidnumber'][0]) > max else max |
|
|
|
return max |
|
|
|
|
|
|
|
@admin_connection_decorator |
|
|
|
def new_user(self, conn, user_dict): |
|
|
|
username = utils.clean_user_name(user_dict['uid']) |
|
|
|
user_dn = "uid=%s,o=People,dc=lilik,dc=it"%username |
|
|
|
mail_dn = "mail=%s,vd=lilik.it,o=hosting,dc=lilik,dc=it"%username |
|
|
|
# print("delete user") |
|
|
|
# conn.delete(user_dn) |
|
|
|
# print("delete mail") |
|
|
|
# conn.delete(mail_dn) |
|
|
|
print(" creating") |
|
|
|
conn.add(user_dn, |
|
|
|
['top', 'inetOrgPerson', 'VirtualMailAccount', 'posixAccount', 'shadowAccount'], |
|
|
|
{'accountactive': "FALSE", |
|
|
|
'cn': 'undefined', |
|
|
|
'delete': "FALSE", |
|
|
|
'gidnumber': 100, |
|
|
|
'givenname': 'undefined', |
|
|
|
'homedirectory': "/home/%s"%username, |
|
|
|
'loginshell': '/bin/bash', |
|
|
|
'mail': username, |
|
|
|
'othertransport': 'phamm:', |
|
|
|
'quota': 1024000, |
|
|
|
'smtpauth': "FALSE", |
|
|
|
'sn': 'undefined', |
|
|
|
'uid': username, |
|
|
|
'uidnumber': self.get_max_uidnumber() + 1, |
|
|
|
'userpassword': '', |
|
|
|
'vdhome': 'undefined', |
|
|
|
'mailbox': 'undefined', |
|
|
|
'lastChange': int(time.time())} |
|
|
|
) |
|
|
|
check_result(conn) |
|
|
|
print(conn.result) |
|
|
|
print("user created") |
|
|
|
conn.add(mail_dn, |
|
|
|
['alias', 'extensibleObject'], |
|
|
|
{'aliasedobjectname': user_dn} |
|
|
|
) |
|
|
|
check_result(conn) |
|
|
|
print(conn.result) |
|
|
|
|
|
|
|
@connection_decorator |
|
|
|
def get_posix_groups(self, conn): |
|
|
|
conn.search(utils.ldap_path(config.GROUP, config.DOMAIN), '(objectclass=posixGroup)', attributes=['*']) |
|
|
|
# return clean_user_name(user_name) |
|
|
|
check_result(conn) |
|
|
|
results = {} |
|
|
|
for group in conn.entries: |
|
|
|
results[str(group.cn)] = list(group.memberUid) if 'memberUid' in group else [] |
|
|
|