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 _______________________________________________ Web-SIG mailing list Web-SIG@python.org Web SIG: http://www.python.org/sigs/web-sig Unsubscribe: http://mail.python.org/mailman/options/web-sig/archive%40mail-archive.com