Using repoze.who Middleware

Middleware Responsibilities

repoze.who as middleware has one major function on ingress: it conditionally places identification and authentication information (including a REMOTE_USER value) into the WSGI environment and allows the request to continue to a downstream WSGI application.

repoze.who as middleware has one major function on egress: it examines the headers set by the downstream application, the WSGI environment, or headers supplied by other plugins and conditionally challenges for credentials.

Lifecycle of a Request

repoze.who performs duties both on middleware “ingress” and on middleware “egress”. The following graphic outlines where it sits in the context of the request and its response:

_images/request-lifecycle.png

Request (Ingress) Stages

_images/ingress.png

repoze.who performs the following operations in the following order during middleware ingress:

  1. Environment Setup

    The middleware adds a number of keys to the WSGI environment:

    repoze.who.plugins

    A reference to the configured plugin set.

    repoze.who.logger

    A reference to the logger configured into the middleware.

    repoze.who.application

    A refererence to the “right-hand” application. The plugins consulted during request classification / identification / authentication may replace this application with another WSGI application, which will be used for the remainder of the current request.

  2. Request Classification

    The middleware hands the WSGI environment to the configured classifier plugin, which is responsible for classifying the request into a single “type”. This plugin must return a single string value classifying the request, e.g., “browser”, “xml-rpc”, “webdav”, etc.

    This classification may serve to filter out plugins consulted later in the request. For instance, a plugin which issued a challenge as an HTML form would be inappropriate for use in requests from an XML-RPC or WebDAV client.

  3. Identification

    Each plugin configured as an identifier for a particular class of request is called to extract identity data (“credentials”) from the WSGI environment.

    For example, a basic auth identifier might use the HTTP_AUTHORIZATION header to find login and password information. Each configured identifier plugin is consulted in turn, and any non-None identities returned are collected into a list to be authenticated.

    Identifiers are also responsible for providing header information used to set and remove authentication information in the response during egress (to “remember” or “forget” the currently-authenticated user).

  4. Authentication

    The middlware consults each plugin configured as an authenticators for a particular class of request, to compare credentials extracted by the identification plugins to a given policy, or set of valid credentials.

    For example, an htpasswd authenticator might look in a file for a user record matching any of the extracted credentials. If it finds one, and if the password listed in the record matches the password in the identity, the userid of the user would be returned (which would be the same as the login name). Successfully-authenticated identities are “weighted”, with the highest weight identity governing the remainder of the request.

  5. Metadata Assignment

    After identifying and authenticating a user, repoze.who consults plugins configured as metadata providers, which may augment the authenticated identity with arbitrary metadata.

    For example, a metadata provider plugin might add the user’s first, middle and last names to the identity. A more specialized metadata provider might augment the identity with a list of role or group names assigned to the user.

Response (Egress) Stages

repoze.who performs the following operations in the following order during middleware egress:

  1. Challenge Decision

    The middleare examines the WSGI environment and the status and headers returned by the downstream application to determine whether a challenge is required. Typically, only the status is used: if it starts with 401, a challenge is required, and the challenge decider returns True.

    This behavior can be replaced by configuring a different challenge_decider plugin for the middleware.

    If a challenge is required, the challenge decider returns True; otherwise, it returns False.

  2. Credentials reset, AKA “forgetting”

    If the challenge decider returns True, the middleware first delegates to the identifier plugin which provided the currently-authenticated identity to “forget” the identity, by adding response headers (e.g., to expire a cookie).

  3. Challenge

    The plugin then consults each of the plugins configured as challengers for the current request classification: the first plugin which returns a non-None WSGI application will be used to perform a challenge.

    Challenger plugins may use application-returned headers, the WSGI environment, and other items to determine what sort of operation should be performed to actuate the challenge.

  4. Remember

    The identifier plugin that the “best” set of credentials came from (if any) will be consulted to “remember” these credentials if the challenge decider returns False.