Archive for May, 2009

NTLM Authentication using IIS, ISAPI-WSGI and cherrypy

(How’s that for a snappy post title?). This is really an aide-memoire for myself since I always make this kind of thing way more complicated than it needs to be. My mission (whether or not I choose to accept it) is to have a web interface to one of our internal apps which should support transparent browser-based authentication but should fail back gracefully to anonymous access. The app in question is a Helpdesk app and some years ago I wrote a cherrypy-based web interface to it since its own desktop interface is woeful. The cherrypy app’s been running fine for some years, with incremental improvements but I’m trying to push it out to a wider (internal) audience and it could do with the speed and stability boost which a fully-fledged webserver can give it.

The machine it’s running on (via the standard cherrypy server on port 8080) is already running IIS and the pywin32 isapi module, nicely extended by the ISAPI-WSGI project, makes transferring the app fairly plain sailing. But one of the benefits of transferring to IIS was to get as smooth a passthrough authentication as possible. I had been using a fairly crude http basic auth with an authentication check at the server end, but that’s far from ideal. I hoped that by switching to IIS (and given that the official company browser is IE) I could just flick a switch and get the browser’s identity transparently.

Well you can, but I put two stumbling blocks in my own path: when it didn’t work immediately I tried to make it far more complicated than I need have rather than looking for a simple solution; and identity isn’t the same as an access token. So, for my future self trying to remember how to do this, and for anyone else looking for this solution, here’s the easy bit. (I’m assuming you’ve installed some kind of ISAPI-WSGI app, altho’ the same pretty much applies elsewhere).

  • In the IIS MMC snap-in find the isapi-wsgi app you’ve installed. Right-click Properties. [Directory Security] tab. Anonymous access and authentication control [Edit]. Leave [Anonymous Access] ticked. Tick [Integrated Windows Authentication]. [Ok] all the way out.
  • In your WSGI app, look for the REMOTE_USER env var. If it’s set, you’ve got a remote user. If it’s not, call start_response (”401 Unauthorized”, [(”www-authenticate”, “NTLM”)]) and return []

That’s the really brief version, and is based around the IIS 5.1 which comes free with WinXP. IE users need do no more. FF users will probably already know that they need to add the web server to the about:config param with the unmemorable name (it’s got “ntlm” and “trusted-uris” in it). Don’t know if Chrome handles this.

For my purposes, I was using cherrypy so — when I get back to work — all I should have to do is: check cherrypy.request.login which keeps track of incoming REMOTE_USER / LOGIN_USER env vars for me; and do the “401 Unauthorized” dance if I need to possibly by means of a simple pre-request cherrypy tool. The graceful anonymity will be implemented by not displaying and/or allowing certain actions if there is no remote user. Not sure yet whether I need to fail back to basic or digest auth.

The trickier bit — and the bit I haven’t yet solved — is translating the “Authorization:” header which the browser sends into something which I can persuade Windows to use to give me a session token. With the session token, I can determine whether my user’s in certain security groups or not. (I can do something from the username alone by querying AD and that’s my fallback plan). The python-ntlm project looks like it’s done all the spadework here, and especially in the clientserver branch but they also talk about the pywin32 sspi module which I’ve so far managed to avoid having anything to do with.

IronPython in Action

I received my copy of IronPython in Action (henceforth IPiA) in the middle of the week, and I’ve spent the last few days going through it on the Tube. What that means, in practice, is that I’ve simply skimmed sections which are code-heavy: I’ve not had my laptop with me and trying to read even a modest one-page explanation of a Windows Form app I find daunting unless I can tap the code in as I go. But I’ve gone through everything else. And I like what I see.

By way of disclosure, I’m given a couple of blushingly generous footnote credits by Michael which naturally leave me feeling well-disposed towards the book as a whole. But even without those, I’d be giving it the thumbs-up. As the authors note early on, a book of this sort is trying to fulfil two expectations: to inform existing .NET users about Python; and to inform existing Python users about .NET. With a very few exceptions I believe it manages at least the second of those two. (I’m not competent to judge the first).

As I noted in my review of Tarek Ziade’s Expert Python Programming, people want different things from their programming books. What suits me in IPiA might not suit someone else. But I find the style to be lightweight enough to avoid pomposity (my own cardinal fault in writing) while not descending into jokey asides so often as to distract. It also keeps the code examples fairly short. Altho’ I personally do prefer self-contained examples every time, I recognise that this isn’t always easy or even possible. And that some people like one growing example app to run through a book.

But the most important win, I think, is managing to write a book about IronPython, not about Python or .NET. Naturally there is an element of explanation involved in both directions when some feature is being introduced or compared. But for the most part you can refer to the appendices which give summaries of Python/.NET if an unfamiliar term arises. For me, this achievement is key to the success of a book like this. If I want to learn Python or .NET I’ll turn to another book or website. Here I want to know what IronPython can do which Python can’t (or better, or faster, or worse) and what IronPython can do which C# can’t (or better etc.). I don’t want to know what .NET can offer as such, altho’ real-word examples are obviously great illustrations. The one place I believe IPiA falls down just a little in this regard is in the chapter on Databases and Web Services. The problem is that IronPython doesn’t seem to bring enough to the table here to distinguish it from the equivalent C# code.

As a long-time user of Python on a Windows platform, I’ve obviously been umming-and-ahing about IronPython for a while. I’m happy with CPython, familiar with it; I’ve written no few lines of code around the Win32 API, all of which disappears when you enter the world of IronPython/.NET. That said, it’s clear that .NET is the future of Windows. As it happens, it looks like we’re about to undertake a project at work based around the Juggernaut Sharepoint and I hope this will provide the incentive for me to have a go with IronPython and see what it can do.

Any version bdist_msi for pure Python packages

A double whammy, courtesy of recent commits by Stephen Bethard and Tarek Ziade: not only is the available-but-undocumented bdist_msi packager now available-and-documented, but it also offers installation into multiple Python installations for pure Python packages. This means that, say, an installer for my Python-only WMI module can now be installed to any Python installation found in the registry. Not only that (which the bdist_wininst installer already offers), but it also offers you the chance to install to an arbitrary location (say if you have Python built under a Subversion checkout).

UPDATE: Brad Allen points out that bdist_msi already allows installation to an arbitrary location (which I didn’t think it did).

Questions and Answers on the Python lists

Over the years of my involvement with the Python community, I have seen many questions asked and answered on the Python lists. I’m a fairly regular watcher on python-list, python-win32 and python-tutor and an occasional on a couple of other lists, including python-dev. For my part, I nearly always access them via their email interface. But other people view them through gmane, Usenet, Google Groups and a handful of web-style mirror sites.

Many people have commented on the generally friendly and helpful atmosphere which prevails on all the Python lists, and justifiably. You get the occasional ding-dong thread or a see-sawing to-and-fro between opposing parties, neither of whom can bring himself to relinquish his own position or to accept the other’s. But even that rarely ends in bloodshed.

But my entirely anecdotal impression is that there is a class of questioner who asks a question and fails to respond when an answer is given. And, as someone who’s provided one or two answers in his time, I’m moved to wonder: why? Is it because the OP feels that no thanks or response is necessary — that the list has done its duty and the matter is closed? Is it because the response took more than a few minutes to come back, and the OP wanted a quick answer or none at all? Is it because the answer doesn’t help but the OP doesn’t feel entitled to come back and ask for more? Is it because the OP expects any response to come to him personally and not to the list as a whole, and so doesn’t keep checking back?

I’ve no idea, and I doubt that one case meets all. As it happens, in answer to help I have offered, I have had many responses on and off-list thanking me, or asking for more information, occasionally offering to buy me a drink! And for all those I am very grateful: this is a friendly community built around the creative art of programming, and it’s nice to know that someone’s benefitted from your help and is grateful in turn.

But it would be a shame if there were a class of user who came, not as a potential contributor to the wider community, but as a mercenary who wants merely to get something from Python and walk away.