[Web-SIG] Standardized configuration

Chris McDonough chrism at plope.com
Sun Jul 17 07:31:20 CEST 2005


On Sat, 2005-07-16 at 23:29 -0500, Ian Bicking wrote:
> There's nothing in WSGI to facilitate introspection.  Sometimes that 
> seems annoying, though I suspect lots of headaches are removed because 
> of it, and I haven't found it to be a stopper yet.  The issue I'm 
> interested in is just how to deliver configuration to middleware.

Whew, I hoped you'd respond. ;-)

It appears that I haven't gotten as far as to want introspection into
the implementation or configuration of a middleware component.  Instead,
I want the ability to declaratively construct a pipeline out of largely
opaque and potentially interdependent (but loosely coupled) WSGI
middleware components, which is another problem entirely.  It seemed
cogent, so I just somewhat belligerently coopted this thread, sorry!

> Because middleware can't be introspected (generally), this makes things 
> like configuration schemas very hard to implement.  It all needs to be 
> late-bound.

The pipeline itself isn't really late bound.  For instance, if I was to
create a WSGI middleware pipeline something like this:

   server <--> session <--> identification <--> authentication <--> 
   <--> challenge <--> application

... session, identification, authentication, and challenge are
middleware components (you'll need to imagine their implementations).
And within a module that started a server, you might end up doing
something like:

def configure_pipeline(app):
    return SessionMiddleware(
            IdentificationMiddleware(
              AuthenticationMiddleware(
                ChallengeMiddleware(app)))))

if __name__ == '__main__':
    app = Application()
    pipeline = configure_pipeline(app)
    server = Server(pipeline)
    server.serve()

The pipeline is static.  When a request comes in, the pipeline itself is
already constructed.  I don't really want a way to prevent "improper"
pipeline construction at startup time (right now anyway), because
failures due to missing dependencies will be fairly obvious.

But some elements of the pipeline at this level of factoring do need to
have dependencies on availability and pipeline placement of the other
elements.  In this example, proper operation of the authentication
component depends on the availability and pipeline placement of the
identification component.  Likewise, the identification component may
depend on values that need to be retrieved from the session component.

I've just seen Phillip's post where he implies that this kind of
fine-grained component factoring wasn't really the initial purpose of
WSGI middleware.  That's kind of a bummer. ;-)

Factoring middleware components in this way seems to provide clear
demarcation points for reuse and maintenance.  For example, I imagined a
declarative security module that might be factored as a piece of
middleware here:  http://www.plope.com/Members/chrism/decsec_proposal .

Of course, this sort of thing doesn't *need* to be middleware.  But
making it middleware feels very right to me in terms of being able to
deglom nice features inspired by Zope and other frameworks into pieces
that are easy to recombine as necessary.  Implementations as WSGI
middleware seems a nice way to move these kinds of features out of our
respective applications and into more application-agnostic pieces that
are very loosely coupled, but perhaps I'm taking it too far.

> > For example, it would be useful in some circumstances to create separate
> > WSGI components for user identification and user authorization.  The
> > process of identification -- obtaining user credentials from a request
> > -- and user authorization  -- ensuring that the user is who he says he
> > is by comparing the credentials against a data source -- are really
> > pretty much distinct operations.  There might also be a "challenge"
> > component which forces a login dialog.
> 
> I've always thought that a 401 response is a good way of indicating 
> that, but not everyone agrees.  (The idea being that the middleware 
> catches the 401 and possibly translates it into a redirect or something.)

Yep.  That'd be a fine signaling mechanism.

> > In practice, I don't know if this is a truly useful separation of
> > concerns that need to be implemented in terms of separate components in
> > the middleware pipeline (I see that paste.login conflates them), it's
> > just an example.  
> 
> Do you mean identification and authentication (you mention authorization 
> above)? 

Aggh.  Yes, I meant to write authentication, sorry.

>  I think authorization is different, and is conflated in 
> paste.login, but I don't have any many use cases where it's a useful 
> distinction.  I guess there's a number of ways of getting a username and 
> password; and to some degree the  authenticator object works at that 
> level of abstraction.  And there's a couple other ways of authenticating 
> a user as well (public keys, IP address, etc).  I've generally used a 
> "user manager" object for this kind of abstraction, with subclassing for 
> different kinds of generality (e.g., the basic abstract class makes 
> username/password logins simple, but a subclass can override that and 
> authenticate based on anything in the request).

Sure.  OTOH, Zope 2 has proven that inheritance makes for a pretty awful
general reuse pattern when things become sufficiently complicated.

> As long as it's properly partitioned, I don't think it's a terribly hard 
> problem.  That is, with proper partitioning the pieces can be 
> recombined, even if the implementations aren't general enough for all 
> cases.  Apache and Zope 2 authentication being examples where the 
> partitioning was done improperly.

Yes.  I think it goes further than that.  For example, I'd like to have
be able to swap out implementations of the following kinds of components
at a level somewhere above my application:

Sessioning
Authentication/identification
Authorization (via something like declarative security based on a path)
Virtual hosting awareness
View lookup
View invocation
Transformation during rendering
Caching

Essentially, as Phillip divined, to do so, I've been trying to construct
a framework-neutral component system out of middleware pieces to do so,
but maybe I need to step back from that a bit.  It sure is tempting,
though. ;-)

- C



More information about the Web-SIG mailing list