Handlers

Almost all stages of a request response are configurable by exporting handlers for given portions of the URL space. Handlers are user-supplied Lisp functions called when the resource requested has an appropriate URL
Function EXPORT-HANDLER, EXPORT-HANDLER-LIST

Syntax:

export-handler url handler &key (match :prefix) (method t) (stage :RESPONSE)

export-handler-list url handlers &key (match :prefix) (method t) (stage :RESPONSE)

Arguments and Values:

url - a URL object. See url-class.lisp

handler - a function of two arguments, returning T (handled) or NIL (try something else)

handlers - a list of handler functions, called in sequence until one of them returns T

match - One of :exact - try this handler when url exactly matches that requested, or :prefix - try when url is a prefix of that requested

method - A list of keywords corresponding to HTTP/1.0 methods (:get :post :put :delete etc), or T meaning match all methods

stage - response stage to call this at - see below

Description: handler may be a function designator or a list whose first element is a symbol naming a function. The function is called with arguments (request rest-of-url-string) - the request that caused it to be invoked, and the portion of the request string left over after matching against the exported url. In the case that handler is a list, the elements of its cdr are also passed (unevaluated) to the function.

Example:

(export-handler (parse-urlstring "http://my.server.com/pages/"
                `(file-request-handler "/var/www/htdocs/")
                :method t)

Those response stages in full:

1) :authentication - who does the user say he is? Is he correct?

2) :authorization - is the user allowed to see this resource?

3) :response - send the resource back or do whever else is appropriate at this stage for the request method

4) :log - do anything else that can be done after the stream to the browser window is closed

n) :error - if a Lisp ERROR is thrown during any of the preceding, run this. Don't otherwise

Producing output:

Usually the :response stage is the one that gets to send back a response. However, any earlier stage can send one if it wants (usually in an atypical situation) and close the stream. If the stream is closed, we skip directly to the :log stage when the current stage is done.

Authentication and authorization:

Identities (usernames, basically) are unique per realm

:authentication handler is responsible for checking that the supplied credentials are correct for the given identity in the given URL space. It will only produce a page if the credentials were not supplied or don't match the claimed identity (and might not necessarily even then)

:authorization handler has to check if the requested action is allowed to the given identity when connecting from the given host name (though note that IP-based authorization is not implemented currently - no point as the proxy loses all the relevant information for us)

For example

0) To use the HTTP authentication methods, make sure that your URL space corresponds to an HTTP realm. You need an :authentication handler that digs for the request header's Authorization: line and shoves a suitable user identifier into (request-user ) or hands out the appopriate 40x error. A null :authorization handler will produce a behaviour like the apache "require valid-user" directive, or you could actually write a handler that checked this to confine it further.

How your application reports "incorrect password" (not authenticated) as distinct from "we believe it's you, but you can't do that" (not authorized) is up to you. Most browsers' user interface to this stuff makes it hard to distinguish the two cases anyway; you might find it's simplest just to put everything in the :authentication handler if the users aren't going to notice the difference.

The make-basic-authentication-handler function exists to make basic authentication more basic. It takes two arguments for realm and password-checking function; the latter should take two arguments username and password and return - on success - a `user' which make-basic-authentication-handler will stick in the request-user slot, or on failure NIL. make-basic-authentication-handler returns a handler suitable for exporting.

1) cookie-based authentication, where the user's browser supplies a cookie that we previously sent him. Our :authentication handler checks the supplied cookie against our internal records, filling in the (request-user ) slot if it matches. Our :authorization handler checks if (request-user ) is one of the users allowed here, and prints a helpful error page if not.

2) ident-based authentication - you don't want to use this for anything serious but in a secure intranet environment it might be appropriate. Suggested implementation route would involve getting apache to do the actual lookup as (a) it won't block, and (b) you'll only end up identing the apache daemon if you do it yourself anyway.

Note

1) that we don't care what you put in the request-user slot provided that your :authentication and :authorization handlers both agree on it. It could be a username, user id, CLOS object defining a user, or whatever.

2) When IP-based access control becomes possible, it could conceivably be used at authentication _or_ authorization stage. We might decide for example that all requests from pc10.foo.com are from John Smith (authenticate the request as from "John Smith") or we might decide that all administrator requests must come from localhost - authentication is identifying the remote user whereas authorization is checking that he's "administrator" and connected from localhost. Clear?