.. _using_middleware: Using :mod:`repoze.who` Middleware ================================== .. _middleware_responsibilities: Middleware Responsibilities --------------------------- :mod:`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. :mod:`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. .. _request_lifecycle: Lifecycle of a Request ---------------------- :mod:`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: .. image:: .static/request-lifecycle.png .. _ingress_stages: Request (Ingress) Stages ++++++++++++++++++++++++ .. image:: .static/ingress.png :mod:`repoze.who` performs the following operations in the following order during middleware ingress: #. 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 remainer of the current request. #. 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. #. 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). #. 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 ndenties are "weighted", with the highest weight identity governing the remainder of the request. #. Metadata Assignment After identifying and authenticating a user, :mod:`repoze.who` consults plugins configured as metadata providers, which may augmented 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. .. _egress_stages: Response (Egress) Stages ++++++++++++++++++++++++ :mod:`repoze.who` performs the following operations in the following order during middleware egress: #. 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. #. 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). #. Challenge The plugin then consults each of the set of plugins configured as challengers for the current request classification: the first plugin which returns a non-None WSGI application will be used 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. #. 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.