Authentication

Author:Etienne Robillard <tkadm30@yandex.com>
Version:0.6.2
Last modified:2017-01-23

Roadmap

In addition to native SQLAlchemy support, active development is in progress to develop a fully functional Authentication and Authorization API pluggable with non-sql databases like Schevo (Durus), MongoDB, and Apache Cassandra.

Implementation

The following components are provided as proof-of-concept to implement a generic cookie-based, non-blocking, authentication app using Schevo and the Xdserver backend.

Core modules provided by the notmm.controllers package:

  • auth - Provides the LoginController middleware, to implement custom cookie-based authentication middlewares with AuthKit.
  • session - Provides the SessionController middleware with thread-local storage access to the current request object.

New extensions implemented in AuthKit:

  • authkit.users.schevo_driver: Authentication and authorization backend for Schevo-based databases.
  • authkit.authorize.decorators: WSGI adaptors version 2 for integrating AuthKit with Django.

Authentication middleware

In a stand-alone application, it is intended that the provided authenticate method may be used for implementing a custom authentication middleware.

Thus, the class notmm.controllers.auth.LoginController can be configured in such ways to handle request and responses to protected URIs to any Django-based app.

Consult the AuthKit documentation for additional details on the authentication and authorization middlewares usage.

Overriding the authenticate method

The LoginController.authenticate method may be subclassed to customize the basic authentication challenge.

class LoginController(SessionController):

    def authenticate(self, username, password):
        if username == password:
            # authentication succeeds, return the username as
            # a true value.
            return username
        else:
            return None

Custom UserManager subclassing

The UserManager class used for delegating unauthorized requests to a Schevo-based User model (extent) is given below. Note that this API is subject to changes and is relatively new.

from notmm.dbapi.orm import RelationProxy
from authkit.users.schevo_driver.model import db
from authkit.users import Users

__all__ = ['UserManager']

class UserManager(Users):
    """
    Creates a composite proxy object for the User Entity.

    >>> manager = UserManager(db.User)
    >>> user = manager.objects.get(username="erob")
    >>> user
    <User account: "Etienne Robillard">
    >>> user.username == "erob"
    True
    """

    objects = None

    # Keep this for compatibility with Pylons ;-)
    api_version = 0.4

    def __init__(self, *args, **kwargs):
        # Obtain a default query set for available
        # User entities
        self.objects = self._default_manager = RelationProxy(db.User)

    def user_exists(self, username):
        #look up the user
        user_object = self.objects.get(username=username)
        if user_object is not None:
            return True
        return False

    def user_has_password(self, username, password):
        u = self.objects.get(username=username)
        if u.f.password.compare(password):
            return True
        return False

Authorization middleware

The authkit.authorize.decorators module provides the glue for tying WSGI components to the Django regex-based URL dispatcher and thus for delegating cookie-based authorization to the UserManager model.

Requirements

  • Requires authkit 0.4.6 or later
  • ...

Get Started

First obtain AuthKit using the provided setup.py script to develop from the source location

$ cd extras/libauthkit
$ sudo python setup.py develop

Examples

Basic Usage

Basic usage, for authentication and authorization using HTTP cookies

if __name__ == '__main__':
    # Load the user-defined development.ini file
    global_conf = loadconf('development.ini')

    # Get the authentication config
    auth_conf = global_conf.get('authkit')

    # Setup the WSGI middleware environment and initialize the LoginController
    # to handles incoming authentication requests.
    wsgi_app = WSGIController(app_conf=global_conf, ...)
    ...
    wsgi_app = LoginController(wsgi_app, auth_conf)

    # serve
    httpserver.serve(wsgi_app)

Sample development.ini

This example assumed you have defined a generic configuration file with a authkit section

[authkit]
# root directory of the database
dbroot = /var/db/blogengine
# authentication/authorization database name
dbname = 'accounts'

# middleware setup
authkit.setup.method = redirect, form, cookie
authkit.setup.enable = true

authkit.redirect.url = /session_login/
# Use the new schevo_04_driver authentication backend :)
authkit.form.authenticate.user.type = authkit.users.schevo_04_driver:UserManager
authkit.cookie.secret = user_id

# don't store the username in plain-text in the cookie. breaks
# compatibility with mod_auth_tkt..
# authkit.cookie.enforce = true
# authkit.cookie.nouserincookie = true
# authkit.cookie.params.expires = 500
authkit.cookie.signoutpath = /session_logout/

View-based authorization using a decorator function

To authorize a user for a particular view, assuming that authentication has been successful (i.e: valid_password returned a True value)

# authorization
from authkit.authorize.decorators import authorize
from authkit.permissions import RemoteUser

@authorize(RemoteUser())
def restricted(request, **kwargs):
    assert 'REMOTE_USER' in request.environ
    template_name = 'restricted.html'
    return direct_to_template(request, template_name, ...)