close Warning: Can't synchronize with repository "(default)" (Unsupported version control system "svn": No module named svn). Look in the Trac log for more information.

Version 12 (modified by cmlenz, 16 years ago) (diff)

--

Framework for Authentication and Authorization

This page describes an experimental branch that adds a simple generic auth framework to Diva.

The main goals of this framework are:

  • Enable relatively easy switching between HTTP authentication (such as Basic or Digest authentication performed by the web server) and form-based authentication.
  • Provide basic primitives to get started with form-based login, while allowing complete customization.
  • Provide convenience functions for checking authorization to perform certain actions.
  • No reliance on a specific backend storage for user profiles and credentials.
  • No restriction to a specific method of controlling access to resources (such as ACLs). Applications can use whatever access control granularity they need.
  • Storage-independent generation and verification of authentication cookies for form-based login.

Possible/peripheral goals:

  • Utility functions for generating and verifying encrypted passwords.
  • WSGI middleware for using HTTP authentication, primarily in the context of the DevelopmentServer

All of the above is implemented on the branch at this point.

Non-goals include:

  • Built-in processes and UI for user registration, activation, password resetting, and other high-level features.

Open Issues

  • Naming: assert_authorized is ugly. ensure_authorized would be better, but still ugly. That the function takes (action, resource) parameters makes it harder to choose a name that “sounds” nice.
    See also: Principal.can(action, resource). Not sure about that one, but at least it's short.
  • Authorization Decorator: Should there be a request handler decorator form for checking authorization? What should it be called?
  • The password encryption utilities are a bit on the silly side. They should either be really useful or get nixed.

High-Level Architecture Stuff

Application Mixin Approach

The current branch defines an AuthMixIn class that auth-enabled applications are supposed to subclass. It adds a couple of method stubs to the Application class, and contributes a request filter that performs authentication.

A concrete application would inherit from AuthMixIn in addition to being derived from Application, and would probably want to implement two methods for handling the domain-specific details of identifying users and controlling their access to certain actions and/or resources. For example:

class MyApp(Application, AuthMixIn):
    ...

    def authenticate(self, username, password=None):
        return User.find(name=username)

    def is_authorized(self, principal, action=None, resource=None):
        if action:
            return action in principal.permissions
        return True

Filters Refactoring

Due to the way application mix-in classes can contribute filters, ordering request filters explicitly becomes too painful. The branch enhances the way request filters are defined by allowing them to declare the abstract service they provide (such as "localization" or "error-handling"), and also declare what services they rely on to do their job. For example:

@filters.register('form-processing', requires=['templating', 'localization'])
def form_filter(request, response, chain):
    ...

The ordering of request filters is then inferred from this dependency information.

Authentication Methods

HTTP Authentication

With HTTP (or “external”) authentication, the actual checking of a users credentials is performed outside of the application code, probably by employing some authentication module at the web server level. In this kind of setup, Diva only reads the result of the authentication process from the REMOTE_USER variable.

Form-based Authentication

With form-based login, the application provides an HTML form that allows the user to enter some kind of identifier and a password. When the form is submitted with valid credentials, a cookie is created that allows the framework to identify the user on subsequent requests.

The framework provides a default form (see FormProcessing), a template, and request handlers for logging in and out. Any of these defaults can be customized or replaced by the application.

Hybrid HTTP/Cookie-based Authentication

This mode allows the use of HTTP authentication without having to protect the entire URL namespace. Only one or more sub-resources (such as /login) are protected by HTTP authentication. When the user visits a protected URL, Diva sets a cookie (in the same manner as with form-based authentication), thereby enabling resources outside of the protected area to identify the user and apply her permissions.

Integration and Utilities

Development Server Integration

As HTTP authentication is generally performed by the web server, testing a web app relying on HTTP authentication is often inconvenient. The Diva DevelopmentServer makes it easy by providing built-in support for HTTP Basic and Digest authentication, which can be enabled simply by specifying a couple of command-line options:

$ ./geddit/app.py --help
Usage: app.py [options]

Options:
  -h, --help            show this help message and exit
  -O name=value         set a configuration option
  -b HOST, --host=HOST  hostname or IP address to bind to (default 127.0.0.1)
  -p PORT, --port=PORT  port number to listen to (default 8080)
  -r, --auto-reload     automatically restart after code changes (default off)

  Authentication:
    -B FILE, --basic=FILE
                        path to an unencrypted password file to use for basic
                        authentication
    -D FILE, --digest=FILE
                        path to a htdigest file to use for authentication
    --realm=REALM       name of the authentication realm (default "Geddit")
    --protect=PATH      path(s) to protect by authentication

  Logging:
    -v, --verbose       print as much as possible
    -q, --quiet         print as little as possible

The --digest option is used to specify the text file containing the credentials for digest authentication, in a format compatible with the Apache htdigest tool. The --basic option allows you to use an unencrypted password file for even simpler setup. The --realm option can be used to specify a different realm, where the default is the name of the Application class. This realm needs to match the realm used in the digest file.

Finally, the --protect option can be used to require authentication only on the specified sub-resources. When the --protect option is not provided, the whole URI space will require authentication. When it is specified, authentication is only required on the specified paths. To protect more than one path, simply specifiy the option as often as you need.

For example:

$ ./geddit/app.py -rv --digest auth.digest --protect /login

Password Management Utilities

The diva.auth module also provides a couple of convenience functions for managing encrypted passwords. These can be useful for applications implementing form-based login, but their use is of course entirely optional.

API Documentation

Error: Macro PythonDoc(branches/experimental/auth-framework, diva.auth) failed
Unsupported version control system "svn": No module named svn
Error: Macro PythonDoc(branches/experimental/auth-framework, diva.ext.wsgiauth) failed
Unsupported version control system "svn": No module named svn