Source code for janua.auth.backend

# -*- Mode: Python; coding: utf-8; indent-tabs-mode: nil; tab-width: 4 -*-
#
# Copyright (c) 2016 Cédric Clerget - HPC Center of Franche-Comté University
#
# This file is part of Janua-SMS
#
# http://github.com/mesocentrefc/Janua-SMS
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation v2.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program.  If not, see <http://www.gnu.org/licenses/>.
#
"""
To implement your own authentication backend, you must inherit from
AuthBackend object.

Put your authentication backend module in **/opt/janua/custom/auth** directory

**Example with local backend:**

.. code-block:: python

   class Local(AuthBackend):
       def authenticate_admin(self, admin, password):
           if not check_password(admin.password, password):
               raise AuthError('Bad password for %s' % admin.login)
"""

from janua.utils.utilities import get_subclasses
from janua.auth import AuthError, AuthConfigError

class AuthBackendManager(object):
    def __init__(self):
        self._pool_backend = {}
        self._pool_backend_name = []

    def register(self, db):
        for cls in get_subclasses(AuthBackend):
            backend = cls(db)
            name = backend.name
            self._pool_backend.update({name: backend})
            self._pool_backend_name.append(name)

    def get(self, name):
        if name in self._pool_backend_name:
            return self._pool_backend[name]

    def list(self):
        return self._pool_backend_name

[docs]class AuthBackend(object): """ Authentication backend object and implement :meth:`.authenticate_admin` method """ config = [] """ List of configuration parameters, each parameters specify: * **description:** a short description * **name:** key name to identify it in :class:`Config <janua.db.database.Config>` table * **type:** type of parameter, possible types: **string, boolean, interger** * **value:** parameter's value .. warning:: Don't put spaces in name as it will be converted to class attributes when backend object is instanciated **Example:** .. code-block:: python config = [ { 'description': 'Uri', 'name': 'ldap_uri', 'type': 'string', 'value': 'ldap://127.0.0.1:389' }, { 'description': 'Bind DN', 'name': 'ldap_bind_dn', 'type': 'string', 'value': 'uid=${login},ou=people,dc=organization,dc=com' }, { 'description': 'TLS support', 'name': 'ldap_tls_support', 'type': 'boolean', 'value': False } ] """ help = None """ Help in HTML format which will be displayed in web interface **Example:** .. code-block:: python help = \"\"\" LDAP configuration help <ul> <li>Uri: ldap uri</li> <li>Bind DN: user DN, where ${login} will be replaced with corresponding login</li> <li>TLS support: enable TLS connection</li> </ul> \"\"\" """ mail_template_creation = 'create_admin' """Mail template to use when an account is created to use this backend""" def __init__(self, db): self.name = self.__class__.__name__.lower() self.db = db self._params = [] for cfg in self.config: if 'name' not in cfg: raise AuthConfigError( 'parameter name is missing in %s auth backend' % self.name ) name = cfg['name'] self._params.append(name) if 'description' not in cfg: raise AuthConfigError( 'parameter description is missing for %s in %s auth backend' % (name, self.name) ) if 'value' not in cfg: raise AuthConfigError( 'parameter value is missing for %s in %s auth backend' % (name, self.name) ) if 'type' not in cfg: raise AuthConfigError( 'parameter type is missing for %s in %s auth backend' % (name, self.name) ) entry = self.db.config.get(name) if entry: value = entry.value self.config[self._params.index(name)]['value'] = value else: value = cfg['value'] setattr(self, name, value) def update_config(self, config): """ Configure backend in database. Raise a :class:`janua.auth.AuthConfigError` exception if configure failed in database .. note:: You don't have to implement this method in your backend :param config: a dictionary corresponding to configuration parameters """ for param, value in config.items(): entry = self.db.config.get(param) if entry: entry.value = value if not self.db.update_entry(entry): raise AuthConfigError('failed to set %s value' % param) else: if param not in self._params: raise AuthConfigError('%s is not a parameter' % param) if not self.db.config.add(param, value): raise AuthConfigError('failed to add %s in database' % param) setattr(self, param, value) self.config[self._params.index(param)]['value'] = value
[docs] def authenticate_admin(self, admin, password): """ Authenticate users. This method doesn't return anything, so in case of authentication error, you must raise :class:`janua.auth.AuthError` exception :param admin: admin database object (:class:`janua.db.database.Admin`) :param password: user password """ raise AuthError('Not supported')