Merge branch 'release/0.1' into production
This commit is contained in:
commit
70bc8f4ff3
25 changed files with 669 additions and 58 deletions
1
.gitignore
vendored
1
.gitignore
vendored
|
@ -39,3 +39,4 @@ Thumbs.db
|
|||
Desktop.ini
|
||||
|
||||
.ropeproject
|
||||
_build/
|
||||
|
|
49
README.rst
49
README.rst
|
@ -4,49 +4,8 @@ gvaldap
|
|||
|
||||
This is the GNUViech Admin LDAP administration tool project.
|
||||
|
||||
Working Environment
|
||||
===================
|
||||
GNUViech Admin is a suite of tools for server management used for hosting
|
||||
customer management at `Jan Dittberner IT-Consulting & -Solutions
|
||||
<http://www.gnuviech-server.de>`_.
|
||||
|
||||
You have several options in setting up your working environment. We recommend
|
||||
using virtualenv to separate the dependencies of your project from your
|
||||
system's python environment. If on Linux or Mac OS X, you can also use
|
||||
virtualenvwrapper to help manage multiple virtualenvs across different
|
||||
projects.
|
||||
|
||||
Virtualenv Only
|
||||
---------------
|
||||
|
||||
First, make sure you are using virtualenv (http://www.virtualenv.org). Once
|
||||
that's installed, create your virtualenv::
|
||||
|
||||
$ virtualenv --distribute gvaldap
|
||||
|
||||
You will also need to ensure that the virtualenv has the project directory
|
||||
added to the path. Adding the project directory will allow `django-admin.py` to
|
||||
be able to change settings using the `--settings` flag.
|
||||
|
||||
Virtualenv with virtualenvwrapper
|
||||
------------------------------------
|
||||
|
||||
In Linux and Mac OSX, you can install virtualenvwrapper
|
||||
(http://virtualenvwrapper.readthedocs.org/en/latest/), which will take care of
|
||||
managing your virtual environments and adding the project path to the
|
||||
`site-directory` for you::
|
||||
|
||||
$ mkdir gvaldap
|
||||
$ mkvirtualenv -a gvaldap gvaldap-dev
|
||||
$ cd gvaldap && add2virtualenv `pwd`
|
||||
|
||||
|
||||
Installation of Dependencies
|
||||
=============================
|
||||
|
||||
Depending on where you are installing dependencies:
|
||||
|
||||
In development::
|
||||
|
||||
$ pip install -r requirements/local.txt
|
||||
|
||||
For production::
|
||||
|
||||
$ pip install -r requirements.txt
|
||||
Read the :doc:`Installation instructions <install>` to get started locally.
|
||||
|
|
5
docs/changelog.rst
Normal file
5
docs/changelog.rst
Normal file
|
@ -0,0 +1,5 @@
|
|||
Changelog
|
||||
=========
|
||||
|
||||
* :release:`0.1 <2014-05-31>`
|
||||
* :feature:`-` intial support for creating LDAP users and groups
|
97
docs/code.rst
Normal file
97
docs/code.rst
Normal file
|
@ -0,0 +1,97 @@
|
|||
==================
|
||||
Code documentation
|
||||
==================
|
||||
|
||||
.. index:: Django
|
||||
|
||||
gvaldap is implemented as `Django`_ project and provides some `Celery`_ tasks.
|
||||
|
||||
.. _Django: https://www.djangoproject.com/
|
||||
.. _Celery: http://www.celeryproject.org/
|
||||
|
||||
|
||||
The project module :py:mod:`gvaldap`
|
||||
====================================
|
||||
|
||||
.. automodule:: gvaldap
|
||||
|
||||
|
||||
:py:mod:`gvaldap.celery`
|
||||
------------------------
|
||||
|
||||
.. automodule:: gvaldap.celery
|
||||
:members:
|
||||
|
||||
|
||||
:py:mod:`gvaldap.urls`
|
||||
----------------------
|
||||
|
||||
.. automodule:: gvaldap.urls
|
||||
|
||||
|
||||
:py:mod:`gvaldap.wsgi`
|
||||
----------------------
|
||||
|
||||
.. automodule:: gvaldap.wsgi
|
||||
:members:
|
||||
|
||||
|
||||
:py:mod:`gvaldap.settings`
|
||||
--------------------------
|
||||
|
||||
.. automodule:: gvaldap.settings
|
||||
|
||||
:py:mod:`gvaldap.settings.base`
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
.. automodule:: gvaldap.settings.base
|
||||
:members:
|
||||
|
||||
:py:mod:`gvaldap.settings.local`
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
.. automodule:: gvaldap.settings.local
|
||||
|
||||
:py:mod:`gvaldap.settings.production`
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
.. automodule:: gvaldap.settings.production
|
||||
|
||||
:py:mod:`gvaldap.settings.test`
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
.. automodule:: gvaldap.settings.test
|
||||
|
||||
|
||||
|
||||
:py:mod:`ldapentities` app
|
||||
==========================
|
||||
|
||||
.. automodule:: ldapentities
|
||||
|
||||
|
||||
:py:mod:`ldapenties.admin`
|
||||
--------------------------
|
||||
|
||||
.. automodule:: ldapentities.admin
|
||||
:members:
|
||||
|
||||
|
||||
:py:mod:`ldapenties.models`
|
||||
---------------------------
|
||||
|
||||
.. automodule:: ldapentities.models
|
||||
:members:
|
||||
|
||||
|
||||
:py:mod:`osusers` app
|
||||
=====================
|
||||
|
||||
.. automodule:: osusers
|
||||
|
||||
:py:mod:`osusers.tasks`
|
||||
-----------------------
|
||||
|
||||
.. automodule:: osusers.tasks
|
||||
:members:
|
||||
:undoc-members:
|
11
docs/conf.py
11
docs/conf.py
|
@ -12,12 +12,13 @@
|
|||
# All configuration values have a default; values that are commented out
|
||||
# serve to show the default.
|
||||
|
||||
#import sys, os
|
||||
import sys
|
||||
import os
|
||||
|
||||
# If extensions (or modules to document with autodoc) are in another directory,
|
||||
# add these directories to sys.path here. If the directory is relative to the
|
||||
# documentation root, use os.path.abspath to make it absolute, like shown here.
|
||||
#sys.path.insert(0, os.path.abspath('.'))
|
||||
sys.path.insert(0, os.path.abspath(os.path.join('..', 'gvaldap')))
|
||||
|
||||
# -- General configuration -----------------------------------------------------
|
||||
|
||||
|
@ -26,11 +27,15 @@
|
|||
|
||||
# Add any Sphinx extension module names here, as strings. They can be extensions
|
||||
# coming with Sphinx (named 'sphinx.ext.*') or your custom ones.
|
||||
extensions = []
|
||||
extensions = ['releases', 'sphinx.ext.autodoc', 'celery.contrib.sphinx']
|
||||
|
||||
# Add any paths that contain templates here, relative to this directory.
|
||||
templates_path = ['_templates']
|
||||
|
||||
releases_issue_uri = 'https://dev.gnuviech-server.de/gvaldap/ticket/%s'
|
||||
|
||||
releases_release_uri = 'https://dev.gnuviech-server.de/gvaldap/milestone/%s'
|
||||
|
||||
# The suffix of source filenames.
|
||||
source_suffix = '.rst'
|
||||
|
||||
|
|
|
@ -1,4 +1,10 @@
|
|||
Deploy
|
||||
========
|
||||
|
||||
This is where you describe how the project is deployed in production.
|
||||
The production deployment for gvaldap is performed using saltstack and consists
|
||||
of the following steps:
|
||||
|
||||
* installation of native dependencies
|
||||
* setup of a virtualenv
|
||||
* installation of gvaldap production dependencies inside the virtualenv
|
||||
* setup of celery worker under control of supervisord
|
||||
|
|
|
@ -3,6 +3,8 @@
|
|||
You can adapt this file completely to your liking, but it should at least
|
||||
contain the root `toctree` directive.
|
||||
|
||||
.. include:: ../README.rst
|
||||
|
||||
Welcome to gvaldap's documentation!
|
||||
====================================
|
||||
|
||||
|
@ -13,8 +15,8 @@ Contents:
|
|||
|
||||
install
|
||||
deploy
|
||||
tests
|
||||
|
||||
code
|
||||
changelog
|
||||
|
||||
|
||||
Indices and tables
|
||||
|
|
|
@ -1,4 +1,84 @@
|
|||
.. index:: installation
|
||||
|
||||
=======
|
||||
Install
|
||||
=======
|
||||
|
||||
This is where you write how to get a new laptop to run this project.
|
||||
Working Environment
|
||||
===================
|
||||
|
||||
You have several options in setting up your working environment. We recommend
|
||||
using virtualenv to separate the dependencies of your project from your
|
||||
system's python environment. If on Linux or Mac OS X, you can also use
|
||||
virtualenvwrapper to help manage multiple virtualenvs across different
|
||||
projects.
|
||||
|
||||
.. index:: virtualenv
|
||||
|
||||
Virtualenv Only
|
||||
---------------
|
||||
|
||||
First, make sure you are using `virtualenv`_. Once that's installed, create
|
||||
your virtualenv:
|
||||
|
||||
.. code-block:: sh
|
||||
|
||||
$ virtualenv --distribute gvaldap
|
||||
|
||||
.. _virtualenv: https://virtualenv.pypa.io/en/latest/
|
||||
|
||||
You will also need to ensure that the virtualenv has the project directory
|
||||
added to the path. Adding the project directory will allow `django-admin.py` to
|
||||
be able to change settings using the `--settings` flag.
|
||||
|
||||
.. index:: virtualenvwrapper
|
||||
|
||||
Virtualenv with virtualenvwrapper
|
||||
------------------------------------
|
||||
|
||||
In Linux and Mac OSX, you can install `virtualenvwrapper
|
||||
<http://virtualenvwrapper.readthedocs.org/en/latest/>`_, which will take care
|
||||
of managing your virtual environments and adding the project path to the
|
||||
`site-directory` for you:
|
||||
|
||||
.. code-block:: sh
|
||||
|
||||
$ mkdir gvaldap
|
||||
$ mkvirtualenv -a gvaldap gvaldap-dev
|
||||
$ cd gvaldap && add2virtualenv `pwd`
|
||||
|
||||
|
||||
.. index:: pip, requirements, dependencies
|
||||
|
||||
Installation of Dependencies
|
||||
=============================
|
||||
|
||||
Depending on where you are installing dependencies:
|
||||
|
||||
In development:
|
||||
|
||||
.. code-block:: sh
|
||||
|
||||
$ pip install -r requirements/local.txt
|
||||
|
||||
For production:
|
||||
|
||||
.. code-block:: sh
|
||||
|
||||
$ pip install -r requirements.txt
|
||||
|
||||
.. index:: celery, worker, ldap queue
|
||||
|
||||
Running the Celery worker
|
||||
=========================
|
||||
|
||||
gvaldap uses the `Celery`_ distributed task queue system. The gvaldap logix is
|
||||
executed by a celery worker. After all dependencies are installed you can go
|
||||
into the gvaldap directory and run the celery worker with:
|
||||
|
||||
.. code-block:: sh
|
||||
|
||||
$ cd gvaldap
|
||||
$ celery -A gvaldap worker -Q ldap -l info
|
||||
|
||||
.. _Celery: http://www.celeryproject.org/
|
||||
|
|
|
@ -0,0 +1,3 @@
|
|||
"""
|
||||
This is the gvaldap project module.
|
||||
"""
|
23
gvaldap/gvaldap/celery.py
Normal file
23
gvaldap/gvaldap/celery.py
Normal file
|
@ -0,0 +1,23 @@
|
|||
"""
|
||||
This module defines the Celery_ app for gvaldap.
|
||||
|
||||
.. _Celery: http://www.celeryproject.org/
|
||||
|
||||
"""
|
||||
from __future__ import absolute_import
|
||||
|
||||
import os
|
||||
|
||||
from celery import Celery
|
||||
|
||||
from django.conf import settings
|
||||
|
||||
os.environ.setdefault('DJANGO_SETTINGS_MODULE',
|
||||
'gvaldap.settings.production')
|
||||
|
||||
|
||||
#: The Celery application
|
||||
app = Celery('gvaldap')
|
||||
|
||||
app.config_from_object('django.conf:settings')
|
||||
app.autodiscover_tasks(lambda: settings.INSTALLED_APPS)
|
|
@ -1 +1,3 @@
|
|||
|
||||
"""
|
||||
This module contains settings for various environments.
|
||||
"""
|
||||
|
|
|
@ -1,5 +1,9 @@
|
|||
"""Common settings and globals."""
|
||||
# -*- coding: utf-8 -*-
|
||||
# pymode:lint_ignore=E501
|
||||
"""
|
||||
Common settings and globals.
|
||||
|
||||
"""
|
||||
|
||||
|
||||
from os.path import abspath, basename, dirname, join, normpath
|
||||
|
@ -12,7 +16,14 @@ from django.core.exceptions import ImproperlyConfigured
|
|||
|
||||
|
||||
def get_env_setting(setting):
|
||||
""" Get the environment setting or return exception """
|
||||
"""
|
||||
Get the environment setting or return exception.
|
||||
|
||||
:param str setting: name of an environment setting
|
||||
:raises ImproperlyConfigured: if the environment setting is not defined
|
||||
:return: environment setting value
|
||||
:rtype: str
|
||||
"""
|
||||
try:
|
||||
return environ[setting]
|
||||
except KeyError:
|
||||
|
@ -216,6 +227,8 @@ DJANGO_APPS = (
|
|||
|
||||
# Apps specific for this project go here.
|
||||
LOCAL_APPS = (
|
||||
'ldapentities',
|
||||
'osusers',
|
||||
)
|
||||
|
||||
# See: https://docs.djangoproject.com/en/dev/ref/settings/#installed-apps
|
||||
|
@ -262,6 +275,12 @@ WSGI_APPLICATION = '%s.wsgi.application' % SITE_NAME
|
|||
########## END WSGI CONFIGURATION
|
||||
|
||||
|
||||
########## LDAP SETTINGS
|
||||
GROUP_BASE_DN = get_env_setting('GVALDAP_BASEDN_GROUP')
|
||||
USER_BASE_DN = get_env_setting('GVALDAP_BASEDN_USER')
|
||||
########## END LDAP SETTINGS
|
||||
|
||||
|
||||
########## SOUTH CONFIGURATION
|
||||
# See: http://south.readthedocs.org/en/latest/installation.html#configuring-your-django-installation
|
||||
INSTALLED_APPS += (
|
||||
|
@ -271,3 +290,13 @@ INSTALLED_APPS += (
|
|||
# Don't need to use South when setting up a test database.
|
||||
SOUTH_TESTS_MIGRATE = False
|
||||
########## END SOUTH CONFIGURATION
|
||||
|
||||
|
||||
########## CELERY CONFIGURATION
|
||||
BROKER_URL = get_env_setting('GVALDAP_BROKER_URL')
|
||||
CELERY_RESULT_BACKEND = 'amqp'
|
||||
CELERY_RESULT_PERSISTENT = True
|
||||
CELERY_TASK_RESULT_EXPIRES = None
|
||||
CELERY_ACCEPT_CONTENT = ['yaml']
|
||||
CELERY_RESULT_SERIALIZER = 'yaml'
|
||||
########## END CELERY CONFIGURATION
|
||||
|
|
|
@ -1,5 +1,8 @@
|
|||
"""Development settings and globals."""
|
||||
# pymode:lint_ignore=W0401,E501
|
||||
"""
|
||||
Development settings and globals based on :py:mod:`gvaldap.settings.base`.
|
||||
|
||||
"""
|
||||
|
||||
from __future__ import absolute_import
|
||||
|
||||
|
|
|
@ -1,5 +1,8 @@
|
|||
"""Production settings and globals."""
|
||||
# pymode:lint_ignore=W0401,E501
|
||||
"""
|
||||
Production settings and globals based on :py:mod:`gvaldap.settings.base`.
|
||||
|
||||
"""
|
||||
|
||||
from __future__ import absolute_import
|
||||
|
||||
|
|
|
@ -1,4 +1,8 @@
|
|||
# pymode:lint_ignore=W0401
|
||||
"""
|
||||
Test settings based on :py:mod:`gvaldap.settings.base`.
|
||||
|
||||
"""
|
||||
from __future__ import absolute_import
|
||||
|
||||
from .base import *
|
||||
|
|
|
@ -1,3 +1,8 @@
|
|||
"""
|
||||
This module defines the main URLConf for gvaldap.
|
||||
|
||||
"""
|
||||
|
||||
from django.conf.urls import patterns, include, url
|
||||
from django.conf import settings
|
||||
|
||||
|
|
|
@ -26,10 +26,10 @@ path.append(SITE_ROOT)
|
|||
# os.environ["DJANGO_SETTINGS_MODULE"] = "jajaja.settings"
|
||||
os.environ.setdefault("DJANGO_SETTINGS_MODULE", "gvaldap.settings.production")
|
||||
|
||||
from django.core.wsgi import get_wsgi_application
|
||||
# This application object is used by any WSGI server configured to use this
|
||||
# file. This includes Django's development server, if the WSGI_APPLICATION
|
||||
# setting points here.
|
||||
from django.core.wsgi import get_wsgi_application
|
||||
application = get_wsgi_application()
|
||||
|
||||
# Apply WSGI middleware here.
|
||||
|
|
7
gvaldap/ldapentities/__init__.py
Normal file
7
gvaldap/ldapentities/__init__.py
Normal file
|
@ -0,0 +1,7 @@
|
|||
"""
|
||||
This app takes care of managing LDAP entities, at the moment these are:
|
||||
|
||||
* LDAP groups (:py:class:`ldapentities.models.LdapGroup`).
|
||||
* LDAP users (:py:class:`ldapentities.models.LdapUser`)
|
||||
|
||||
"""
|
39
gvaldap/ldapentities/admin.py
Normal file
39
gvaldap/ldapentities/admin.py
Normal file
|
@ -0,0 +1,39 @@
|
|||
"""
|
||||
Admin classes for easy `django admin`_ based administration of LDAP entities.
|
||||
|
||||
.. _django admin: https://docs.djangoproject.com/en/dev/ref/contrib/admin/
|
||||
|
||||
"""
|
||||
|
||||
from django.contrib import admin
|
||||
|
||||
from .models import (
|
||||
LdapGroup,
|
||||
LdapUser,
|
||||
)
|
||||
|
||||
|
||||
class LdapGroupAdmin(admin.ModelAdmin):
|
||||
"""
|
||||
Admin class for :py:class:`LDAP group <ldapentities.models.LdapGroup>`
|
||||
entities.
|
||||
|
||||
"""
|
||||
exclude = ['dn', 'members']
|
||||
list_display = ['name', 'gid']
|
||||
search_fields = ['name']
|
||||
|
||||
|
||||
class LdapUserAdmin(admin.ModelAdmin):
|
||||
"""
|
||||
Admin class for :py:class:`LDAP user <ldapentities.models.LdapUser>`
|
||||
entities.
|
||||
|
||||
"""
|
||||
exclude = ['dn', 'password']
|
||||
list_display = ['username', 'uid']
|
||||
search_fields = ['username']
|
||||
|
||||
|
||||
admin.site.register(LdapGroup, LdapGroupAdmin)
|
||||
admin.site.register(LdapUser, LdapUserAdmin)
|
108
gvaldap/ldapentities/models.py
Normal file
108
gvaldap/ldapentities/models.py
Normal file
|
@ -0,0 +1,108 @@
|
|||
"""
|
||||
This module defines models for LDAP entities.
|
||||
|
||||
The models are based on :py:class:`ldapmodels.Model` from `django-ldapdb`_.
|
||||
|
||||
.. _django-ldapdb: https://github.com/jlaine/django-ldapdb#readme
|
||||
|
||||
"""
|
||||
|
||||
from django.conf import settings
|
||||
from django.utils.encoding import python_2_unicode_compatible
|
||||
from ldapdb.models.fields import (
|
||||
CharField,
|
||||
IntegerField,
|
||||
ListField,
|
||||
)
|
||||
import ldapdb.models as ldapmodels
|
||||
|
||||
from passlib.hash import ldap_salted_sha1
|
||||
|
||||
|
||||
@python_2_unicode_compatible
|
||||
class LdapGroup(ldapmodels.Model):
|
||||
"""
|
||||
Class for representing an LDAP group entity with objectClass `posixGroup`.
|
||||
|
||||
.. seealso:: :rfc:`2307#section-4`
|
||||
|
||||
.. py:attribute:: base_dn
|
||||
|
||||
a string containing the LDAP base distinguished name
|
||||
|
||||
.. py:attribute:: members
|
||||
|
||||
contains the list of `memberUid` attributes
|
||||
|
||||
"""
|
||||
# LDAP meta-data
|
||||
base_dn = settings.GROUP_BASE_DN
|
||||
#: list of object classes
|
||||
object_classes = ['posixGroup']
|
||||
|
||||
# posixGroup attributes
|
||||
#: group id (`gidNumber`)
|
||||
gid = IntegerField(db_column='gidNumber', unique=True)
|
||||
#: group name (`cn`)
|
||||
name = CharField(db_column='cn', max_length=200, primary_key=True)
|
||||
#: group description (`description`)
|
||||
description = CharField(db_column='description')
|
||||
members = ListField(db_column='memberUid', blank=True)
|
||||
|
||||
def __str__(self):
|
||||
"""
|
||||
Get a string representation of this LDAP group.
|
||||
"""
|
||||
return self.name
|
||||
|
||||
|
||||
@python_2_unicode_compatible
|
||||
class LdapUser(ldapmodels.Model):
|
||||
"""
|
||||
Class for representing an LDAP user entity with objectClasses `account` and
|
||||
`posixAccount`.
|
||||
|
||||
.. seealso:: :rfc:`2307#section-4`, :rfc:`4524#section-3.1`
|
||||
|
||||
.. py:attribute:: base_dn
|
||||
|
||||
a string containing the LDAP base distinguished name
|
||||
|
||||
"""
|
||||
base_dn = settings.USER_BASE_DN
|
||||
#: list of object classes
|
||||
object_classes = ['account', 'posixAccount']
|
||||
|
||||
# posixAccount
|
||||
#: user id (`uidNumber`)
|
||||
uid = IntegerField(db_column='uidNumber', unique=True)
|
||||
#: group id (`gidNumber`) of the user's primary group
|
||||
group = IntegerField(db_column='gidNumber')
|
||||
#: GECOS field (`gecos`)
|
||||
gecos = CharField(db_column='gecos')
|
||||
#: home directory (`homeDirectory`)
|
||||
home_directory = CharField(db_column='homeDirectory')
|
||||
#: login shell (`loginShell`)
|
||||
login_shell = CharField(db_column='loginShell', default='/bin/bash')
|
||||
#: user name (`uid`)
|
||||
username = CharField(db_column='uid', primary_key=True)
|
||||
#: password (`userPassword`) in an LDAP compatible format
|
||||
password = CharField(db_column='userPassword')
|
||||
#: common name (`cn`)
|
||||
common_name = CharField(db_column='cn')
|
||||
|
||||
def __str__(self):
|
||||
"""
|
||||
Get a string representation of this LDAP user.
|
||||
"""
|
||||
return self.username
|
||||
|
||||
def set_password(self, password):
|
||||
"""
|
||||
Sets the encrypted password of the user from the given clear text
|
||||
password.
|
||||
|
||||
:param str password: the clear text password
|
||||
|
||||
"""
|
||||
self.password = ldap_salted_sha1.encrypt(password)
|
3
gvaldap/osusers/__init__.py
Normal file
3
gvaldap/osusers/__init__.py
Normal file
|
@ -0,0 +1,3 @@
|
|||
"""
|
||||
This module contains :py:mod:`osusers.tasks`.
|
||||
"""
|
3
gvaldap/osusers/models.py
Normal file
3
gvaldap/osusers/models.py
Normal file
|
@ -0,0 +1,3 @@
|
|||
"""
|
||||
Empty models module required for Django to accept this as an app.
|
||||
"""
|
219
gvaldap/osusers/tasks.py
Normal file
219
gvaldap/osusers/tasks.py
Normal file
|
@ -0,0 +1,219 @@
|
|||
"""
|
||||
This module defines `Celery`_ tasks to manage LDAP entities.
|
||||
|
||||
.. _Celery: http://www.celeryproject.org/
|
||||
|
||||
"""
|
||||
|
||||
from __future__ import absolute_import
|
||||
|
||||
from django.core.exceptions import ObjectDoesNotExist
|
||||
from celery import shared_task
|
||||
from celery.utils.log import get_task_logger
|
||||
from celery.exceptions import Reject
|
||||
|
||||
from ldapentities.models import (
|
||||
LdapGroup,
|
||||
LdapUser,
|
||||
)
|
||||
|
||||
|
||||
_logger = get_task_logger(__name__)
|
||||
|
||||
|
||||
@shared_task
|
||||
def create_ldap_group(groupname, gid, descr):
|
||||
"""
|
||||
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 descr: description text for the group
|
||||
:return: the distinguished name of the group
|
||||
:rtype: str
|
||||
"""
|
||||
try:
|
||||
ldapgroup = LdapGroup.objects.get(name=groupname)
|
||||
_logger.info(
|
||||
'ldap group with dn {0} already exists'.format(ldapgroup.dn)
|
||||
)
|
||||
ldapgroup.gid = gid
|
||||
except LdapGroup.DoesNotExist:
|
||||
ldapgroup = LdapGroup(gid=gid, name=groupname)
|
||||
ldapgroup.description = descr
|
||||
ldapgroup.save()
|
||||
return 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: the distinguished name of the user
|
||||
:rtype: str
|
||||
|
||||
"""
|
||||
try:
|
||||
ldapuser = LdapUser.objects.get(username=username)
|
||||
_logger.info(
|
||||
'ldap user with dn {0} already exists'.format(ldapuser.dn)
|
||||
)
|
||||
except LdapUser.DoesNotExist:
|
||||
ldapuser = LdapUser(username=username)
|
||||
try:
|
||||
ldapgroup = LdapGroup.objects.get(gid=gid)
|
||||
except ObjectDoesNotExist as exc:
|
||||
_logger.info('ldap group with gid {0} does not exist')
|
||||
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)
|
||||
if ldapuser.username in ldapgroup.members:
|
||||
_logger.info('user {0} is already member of {1}'.format(
|
||||
ldapuser.username, ldapgroup.dn)
|
||||
)
|
||||
else:
|
||||
ldapgroup.members.append(ldapuser.username)
|
||||
ldapgroup.save()
|
||||
ldapuser.save()
|
||||
return ldapuser.dn
|
||||
|
||||
|
||||
@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: True if the user has been added to the group otherwise False
|
||||
:rtype: boolean
|
||||
|
||||
"""
|
||||
try:
|
||||
ldapgroup = LdapGroup.objects.get(name=groupname)
|
||||
ldapuser = LdapUser.objects.get(username=username)
|
||||
except LdapGroup.DoesNotExist:
|
||||
_logger.error('ldap group {0} does not exist'.format(groupname))
|
||||
except LdapUser.DoesNotExist as exc:
|
||||
_logger.error('ldap user {0} does not exist'.format(username))
|
||||
self.retry(exc=exc, time_limit=5)
|
||||
else:
|
||||
if not ldapuser.username in ldapgroup.members:
|
||||
ldapgroup.members.append(ldapuser.username)
|
||||
ldapgroup.save()
|
||||
else:
|
||||
_logger.info('ldap user {0} is already in group {1}'.format(
|
||||
ldapuser.username, ldapgroup.dn)
|
||||
)
|
||||
return True
|
||||
return False
|
||||
|
||||
|
||||
@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: True if the user has been removed, False otherwise
|
||||
:rtype: boolean
|
||||
|
||||
"""
|
||||
ldapgroup = LdapGroup.objects.get(name=groupname)
|
||||
ldapuser = LdapUser.objects.get(username=username)
|
||||
performdelete = ldapuser.username in ldapgroup.members
|
||||
if performdelete:
|
||||
ldapgroup.members.remove(ldapuser.username)
|
||||
ldapgroup.save()
|
||||
return performdelete
|
||||
|
||||
|
||||
@shared_task
|
||||
def delete_ldap_user(username):
|
||||
"""
|
||||
This task deletes the given user.
|
||||
|
||||
:param str username: the user name
|
||||
:return: True if the user has been deleted, False otherwise
|
||||
:rtype: boolean
|
||||
|
||||
"""
|
||||
try:
|
||||
ldapuser = LdapUser.objects.get(username=username)
|
||||
except LdapUser.DoesNotExist:
|
||||
_logger.info('there is no ldap user with uid {0}'.format(
|
||||
username)
|
||||
)
|
||||
else:
|
||||
try:
|
||||
ldapgroup = LdapGroup.objects.get(gid=ldapuser.group)
|
||||
except LdapGroup.DoesNotExist:
|
||||
_logger.info('group {0} for user {1} does not exist'.format(
|
||||
ldapuser.group, ldapuser.username)
|
||||
)
|
||||
else:
|
||||
if ldapuser.username in ldapgroup.members:
|
||||
ldapgroup.members.remove(ldapuser.username)
|
||||
ldapgroup.save()
|
||||
ldapuser.delete()
|
||||
return True
|
||||
return False
|
||||
|
||||
|
||||
@shared_task
|
||||
def delete_ldap_group_if_empty(groupname):
|
||||
"""
|
||||
This task deletes the given group.
|
||||
|
||||
:param str groupname: the group name
|
||||
:return: True if the user has been deleted, False otherwise
|
||||
:rtype: boolean
|
||||
|
||||
"""
|
||||
try:
|
||||
ldapgroup = LdapGroup.objects.get(name=groupname)
|
||||
except LdapGroup.DoesNotExist:
|
||||
_logger.info('ldap group with name {0} does not exist'.format(
|
||||
groupname)
|
||||
)
|
||||
else:
|
||||
if len(ldapgroup.members) == 0:
|
||||
ldapgroup.delete()
|
||||
return True
|
||||
else:
|
||||
_logger.info('ldap group {0} still has {1} members'.format(
|
||||
ldapgroup.dn, len(ldapgroup.members))
|
||||
)
|
||||
return False
|
|
@ -5,3 +5,6 @@ django-braces==1.4.0
|
|||
django-model-utils==2.0.3
|
||||
logutils==0.3.3
|
||||
South==0.8.4
|
||||
celery==3.1.11
|
||||
passlib==1.6.2
|
||||
pyaml==14.05.7
|
||||
|
|
|
@ -3,3 +3,5 @@
|
|||
coverage==3.7.1
|
||||
django-debug-toolbar==1.2.1
|
||||
Sphinx==1.2.2
|
||||
sqlparse==0.1.11
|
||||
releases==0.6.1
|
||||
|
|
Loading…
Reference in a new issue