This commit reorganizes the package structure. The gvaldap.settings modules have been merged. The gvaldap.ldaptasks module has been move up one level to have task names without the gvaldap prefix. isort control instructions have been added to setup.cfg.
364 lines
12 KiB
Python
364 lines
12 KiB
Python
"""
|
|
This module defines `Celery`_ tasks to manage LDAP entities.
|
|
|
|
.. _Celery: http://www.celeryproject.org/
|
|
|
|
"""
|
|
|
|
from __future__ import absolute_import
|
|
|
|
from copy import deepcopy
|
|
|
|
from celery import shared_task
|
|
from celery.exceptions import Reject
|
|
from celery.utils.log import get_task_logger
|
|
|
|
from django.core.exceptions import ObjectDoesNotExist
|
|
|
|
from ldapentities.models import LdapGroup, LdapUser
|
|
|
|
_LOGGER = get_task_logger(__name__)
|
|
|
|
|
|
@shared_task
|
|
def create_ldap_group(groupname, gid, description):
|
|
"""
|
|
This task creates an :py:class:`LDAP group <ldapentities.models.LdapGroup>`
|
|
if it does not exist yet.
|
|
|
|
If a group with the given name exists its group id and description
|
|
attributes are updated.
|
|
|
|
:param str groupname: the group name
|
|
:param int gid: the group id
|
|
:param str description: description text for the group
|
|
:return: dictionary containing groupname, gid, description and
|
|
:py:const:`group_dn` set to the distinguished name of the newly created
|
|
or existing LDAP group
|
|
:rtype: dict
|
|
|
|
"""
|
|
try:
|
|
ldapgroup = LdapGroup.objects.get(name=groupname)
|
|
_LOGGER.info(
|
|
"LDAP group %s with groupname %s already exists", ldapgroup.dn, groupname
|
|
)
|
|
ldapgroup.gid = gid
|
|
except LdapGroup.DoesNotExist:
|
|
ldapgroup = LdapGroup(gid=gid, name=groupname)
|
|
_LOGGER.info("created LDAP group %s", ldapgroup.dn)
|
|
ldapgroup.description = description
|
|
ldapgroup.save()
|
|
_LOGGER.info("set description of LDAP group %s", ldapgroup.dn)
|
|
return {
|
|
"groupname": groupname,
|
|
"gid": gid,
|
|
"description": description,
|
|
"group_dn": ldapgroup.dn,
|
|
}
|
|
|
|
|
|
@shared_task
|
|
def create_ldap_user(username, uid, gid, gecos, homedir, shell, password):
|
|
"""
|
|
This task creates an :py:class:`LDAP user <ldapentities.models.LdapUser>`
|
|
if it does not exist yet.
|
|
|
|
The task is rejected if the primary group of the user is not defined.
|
|
|
|
The user's fields are updated if the user already exists.
|
|
|
|
:param str username: the user name
|
|
:param int uid: the user id
|
|
:param int gid: the user's primary group's id
|
|
:param str gecos: the text for the GECOS field
|
|
:param str homedir: the user's home directory
|
|
:param str shell: the user's login shell
|
|
:param str or None password: the clear text password, if :py:const:`None`
|
|
is passed the password is not touched
|
|
:raises celery.exceptions.Reject: if the specified primary group does not
|
|
exist
|
|
:return: dictionary containing username, uid, gid, gecos, homedir, shell,
|
|
password and :py:const:`user_dn` set to the distinguished name of the
|
|
newly created or existing LDAP user
|
|
:rtype: dict
|
|
|
|
"""
|
|
try:
|
|
ldapuser = LdapUser.objects.get(username=username)
|
|
_LOGGER.info(
|
|
"LDAP user %s with username %s already exists", ldapuser.dn, username
|
|
)
|
|
except LdapUser.DoesNotExist:
|
|
ldapuser = LdapUser(username=username)
|
|
try:
|
|
ldapgroup = LdapGroup.objects.get(gid=gid)
|
|
except ObjectDoesNotExist as exc:
|
|
_LOGGER.error("LDAP group with gid %d does not exist", gid)
|
|
raise Reject(exc, requeue=False)
|
|
ldapuser.uid = uid
|
|
ldapuser.group = gid
|
|
ldapuser.gecos = gecos
|
|
ldapuser.home_directory = homedir
|
|
ldapuser.login_shell = shell
|
|
ldapuser.username = username
|
|
ldapuser.common_name = username
|
|
if password is not None:
|
|
ldapuser.set_password(password)
|
|
_LOGGER.info("set password for LDAP user %s", ldapuser.dn)
|
|
ldapuser.save()
|
|
_LOGGER.info("LDAP user %s created", ldapuser.dn)
|
|
if ldapuser.username in ldapgroup.members:
|
|
_LOGGER.info(
|
|
"LDAP user %s is already member of LDAP group %s", ldapuser.dn, ldapgroup.dn
|
|
)
|
|
else:
|
|
ldapgroup.members.append(ldapuser.username)
|
|
ldapgroup.save()
|
|
_LOGGER.info(
|
|
"LDAP user %s has been added to LDAP group %s", ldapuser.dn, ldapgroup.dn
|
|
)
|
|
return {
|
|
"username": username,
|
|
"uid": uid,
|
|
"gid": gid,
|
|
"gecos": gecos,
|
|
"homedir": homedir,
|
|
"shell": shell,
|
|
"user_dn": ldapuser.dn,
|
|
}
|
|
|
|
|
|
@shared_task
|
|
def set_ldap_user_password(username, password):
|
|
"""
|
|
This task sets the password of an existing :py:class:`LDAP user
|
|
<ldapentities.models.LdapUser>`.
|
|
|
|
:param str username: the user name
|
|
:param str password: teh clear text password
|
|
:return: dictionary containing the username and a flag
|
|
:py:const:`password_set` that is set to :py:const:`True` if the
|
|
password has been set, :py:const:`False` if the user does not exist.
|
|
:rtype: dict
|
|
|
|
"""
|
|
retval = {"username": username, "password_set": False}
|
|
try:
|
|
ldapuser = LdapUser.objects.get(username=username)
|
|
except LdapUser.DoesNotExist:
|
|
_LOGGER.info("there is no LDAP user with username %s", username)
|
|
return retval
|
|
ldapuser.set_password(password)
|
|
ldapuser.save()
|
|
_LOGGER.info("set new password for LDAP user %s", ldapuser.dn)
|
|
retval["password_set"] = True
|
|
return retval
|
|
|
|
|
|
@shared_task(bind=True)
|
|
def add_ldap_user_to_group(self, username, groupname):
|
|
"""
|
|
This task adds the specified user to the given group.
|
|
|
|
This task does nothing if the user is already member of the group.
|
|
|
|
:param str username: the user name
|
|
:param str groupname: the group name
|
|
:raises celery.exceptions.Retry: if the user does not exist yet,
|
|
:py:func:`create_ldap_user` should be called before
|
|
:return: dictionary containing the username, groupname and a flag
|
|
:py:const`added` that is as a :py:const:`True` if the user has been
|
|
added to the group otherwise to :py:const:`False`
|
|
:rtype: dict
|
|
|
|
"""
|
|
retval = {"username": username, "groupname": groupname, "added": False}
|
|
try:
|
|
ldapgroup = LdapGroup.objects.get(name=groupname)
|
|
ldapuser = LdapUser.objects.get(username=username)
|
|
except LdapGroup.DoesNotExist:
|
|
_LOGGER.error("LDAP group with groupname %s does not exist", groupname)
|
|
except LdapUser.DoesNotExist as exc:
|
|
_LOGGER.error("LDAP user with username %s does not exist", username)
|
|
self.retry(exc=exc, time_limit=5)
|
|
else:
|
|
if ldapuser.username not in ldapgroup.members:
|
|
ldapgroup.members.append(ldapuser.username)
|
|
ldapgroup.save()
|
|
_LOGGER.info(
|
|
"LDAP user %s has been added to LDAP group %s",
|
|
ldapuser.username,
|
|
ldapgroup.dn,
|
|
)
|
|
else:
|
|
_LOGGER.info(
|
|
"LDAP user %s is already in LDAP group %s",
|
|
ldapuser.username,
|
|
ldapgroup.dn,
|
|
)
|
|
retval["added"] = True
|
|
return retval
|
|
|
|
|
|
@shared_task
|
|
def remove_ldap_user_from_group(username, groupname):
|
|
"""
|
|
This task removes the given user from the given group.
|
|
|
|
:param str username: the user name
|
|
:param str groupname: the group name
|
|
:return: dictionary containing the input parameters and a flag
|
|
:py:const:`removed` that is set to :py:const:`True` if the user has
|
|
been removed, False otherwise
|
|
:rtype: dict
|
|
|
|
"""
|
|
retval = {"username": username, "groupname": groupname, "removed": False}
|
|
try:
|
|
ldapgroup = LdapGroup.objects.get(name=groupname)
|
|
ldapuser = LdapUser.objects.get(username=username)
|
|
except LdapGroup.DoesNotExist:
|
|
_LOGGER.error("LDAP group with groupname %s does not exist", groupname)
|
|
except LdapUser.DoesNotExist:
|
|
_LOGGER.error("LDAP user with username %s does not exist", username)
|
|
else:
|
|
if ldapuser.username in ldapgroup.members:
|
|
ldapgroup.members.remove(ldapuser.username)
|
|
_LOGGER.info(
|
|
"removed LDAP user %s from LDAP group %s", ldapuser.dn, ldapgroup.dn
|
|
)
|
|
ldapgroup.save()
|
|
retval["removed"] = True
|
|
else:
|
|
_LOGGER.info(
|
|
"LDAP user %s is not a member of LDAP group %s",
|
|
ldapuser.dn,
|
|
ldapgroup.dn,
|
|
)
|
|
return retval
|
|
|
|
|
|
@shared_task
|
|
def delete_ldap_user(username, *args, **kwargs):
|
|
"""
|
|
This task deletes the given user.
|
|
|
|
:param str username: the user name
|
|
:return: dictionary containing the username and a flag :py:const:`deleted`
|
|
that is set to :py:const:`True` if the user has been deleted and is set
|
|
to :py:const:`False` otherwise
|
|
:rtype: dict
|
|
|
|
.. note::
|
|
|
|
This variant can only be used at the beginning of a Celery task chain
|
|
or as a standalone task.
|
|
|
|
Use :py:func:`ldaptasks.tasks.delete_ldap_user_chained` at other
|
|
positions in the task chain
|
|
|
|
"""
|
|
retval = {"username": username, "deleted": False}
|
|
try:
|
|
ldapuser = LdapUser.objects.get(username=username)
|
|
except LdapUser.DoesNotExist:
|
|
_LOGGER.info("there is no LDAP user with username %s", username)
|
|
else:
|
|
try:
|
|
ldapgroup = LdapGroup.objects.get(gid=ldapuser.group)
|
|
except LdapGroup.DoesNotExist:
|
|
_LOGGER.info(
|
|
"LDAP group %s of LDAP user %s does not exist",
|
|
ldapuser.group,
|
|
ldapuser.dn,
|
|
)
|
|
else:
|
|
if ldapuser.username in ldapgroup.members:
|
|
ldapgroup.members.remove(ldapuser.username)
|
|
ldapgroup.save()
|
|
_LOGGER.info(
|
|
"removed LDAP user %s from LDAP group %s", ldapuser.dn, ldapgroup.dn
|
|
)
|
|
userdn = ldapuser.dn
|
|
ldapuser.delete()
|
|
_LOGGER.info("deleted LDAP user %s", userdn)
|
|
retval["deleted"] = True
|
|
return retval
|
|
|
|
|
|
@shared_task
|
|
def delete_ldap_user_chained(previous_result, *args, **kwargs):
|
|
"""
|
|
This task deletes the given user.
|
|
|
|
:param dict previous_result: a dictionary describing the result of the
|
|
previous step in the Celery task chain. This dictionary must contain a
|
|
:py:const:`username` key
|
|
:return: a copy of the :py:obj:`previous_result` dictionary with a new
|
|
:py:const:`deleted` key set to :py:const:`True` if the user has been
|
|
deleted and set to :py:const:`False` otherwise
|
|
:rtype: dict
|
|
|
|
"""
|
|
username = previous_result["username"]
|
|
retval = deepcopy(previous_result)
|
|
retval.update(delete_ldap_user(username))
|
|
return retval
|
|
|
|
|
|
@shared_task
|
|
def delete_ldap_group_if_empty(groupname):
|
|
"""
|
|
This task deletes the given group if it is empty.
|
|
|
|
:param str groupname: the group name
|
|
:return: dictionary that contains the groupname and a flag
|
|
:py:const:`deleted` that is set to :py:const:`True` if the group has
|
|
been deleted and is set to :py:const:`False` otherwise
|
|
:rtype: dict
|
|
|
|
"""
|
|
retval = {"groupname": groupname, "deleted": False}
|
|
try:
|
|
ldapgroup = LdapGroup.objects.get(name=groupname)
|
|
except LdapGroup.DoesNotExist:
|
|
_LOGGER.info("LDAP group with groupname %s does not exist", groupname)
|
|
else:
|
|
if len(ldapgroup.members) == 0:
|
|
groupdn = ldapgroup.dn
|
|
ldapgroup.delete()
|
|
_LOGGER.info("deleted LDAP group %s", groupdn)
|
|
retval["deleted"] = True
|
|
else:
|
|
_LOGGER.info(
|
|
"LDAP group %s has not been deleted. It still has %d members",
|
|
ldapgroup.dn,
|
|
len(ldapgroup.members),
|
|
)
|
|
return retval
|
|
|
|
|
|
@shared_task
|
|
def delete_ldap_group(groupname):
|
|
"""
|
|
This task deletes the given group.
|
|
|
|
:param str groupname: the group name
|
|
:return: dictionary that contains the groupname and a flag
|
|
:py:const:`deleted` that is set to :py:const:`True` if the group has
|
|
been deleted and is set to :py:const:`False` otherwise
|
|
:rtype: dict
|
|
|
|
"""
|
|
retval = {"groupname": groupname, "deleted": False}
|
|
try:
|
|
ldapgroup = LdapGroup.objects.get(name=groupname)
|
|
except LdapGroup.DoesNotExist:
|
|
_LOGGER.info("LDAP group with name %s does not exist", groupname)
|
|
else:
|
|
groupdn = ldapgroup.dn
|
|
ldapgroup.delete()
|
|
_LOGGER.info("deleted LDAP group %s", groupdn)
|
|
retval["deleted"] = True
|
|
return retval
|