Home
entries friends calendar user info Scribbles in the Dark
Hali Boat Party
stranger than the night where black stars rise
puzzlement
[info]puzzlement
Add to Memories
Tell a Friend

I would really have to work up to living alone, it's clear. Andrew's been away this week and although it has hardly been a reprise of the great May 2009 ordering-pizza-so-I-wouldn't-have-to-leave-the-house-for-days disaster (I was pretty sick, OK?) the last couple of days have been fairly bad.

Mum was here Monday and Tuesday nights and that was companionable and pleasant. On Wednesday around the time she left it was clear to me that I was starting to get a cold of some kind, which quickly degraded into me losing a yoga mat while doing errands in the Macquarie Centre — not something people find unamusing the next day, have you found a yoga mat in here?, and also, no they hadn't — then heading to the implied yoga class and getting so dizzy that my hearing dropped away. (Andrew tells me he's had that sensation before, I tend to have vision rather than auditory problems when dizzy, normally.)

The trouble with exercise is that clearly you can lay off it if you know prior to doing it that you're sick, but you don't always know beforehand, and if you don't you find out with considerable drama. I didn't want to tell the teacher about it either, because this class is very very careful about my pregnancy already in a way that I find a bit annoying to deal with. I know that it's a very weird time for my abdominal muscles, yes, and lying on my stomach is really uncomfortable, but please let me be the judge of my own upper arm strength. The weight gain is only about 10% over my starting weight.

Last night I pushed out a major task that, I am not kidding, has been a couple of years in the making, although I did spend most of that time intending to get around to it rather than doing things. I had no idea how stressful the immediate leadup had been frankly until I spent half of last night having my old style semi-hallucinations about it. (Possibly I had a mild fever.) The hallucinations are really a particularly annoying unrestful sort of semi-dream state, where time passes extremely slowly and dream people argue with each other incoherently. I used to have a night of that with every new job I got. It tends to stop if I have my eyes open. Keeping them open is a problem.

By the time this morning came around, I was bloody tired, and utterly socially incoherent. Was that a joke you made there? Or a meta-joke? Would it be better if I played along, or if I got cranky? I'm especially bad, when tired, at geek social jokes, which tend to revolve around identifying something vaguely ambiguous in someone's phrasing, choosing the obviously wrong interpretation, and making them stand by it.

So, that was 48 hours of my life I could have lived without. Janus has been making himself a bit scarce: I wouldn't kick my housing either, if it was in that kind of mood. He has stuck with small rearrangements.

It's not that I get sick more, I think, when Andrew is away, it's that a small change in my energy levels makes it such a pain to care for myself. And pregnancy plus illness is not really small, not in the first or third trimesters.

I was going to take myself to Sculptures By the Sea tomorrow, but with my increasingly unpleasant reaction to walking around and actual sickness I don't think I can, sensibly at any rate. It's two trains and a bus in each direction, and then a slow and hilly walk. (Everyone else in the world who owns a car is thinking uh huh, that car-free caper is still ludicrous, but actually, here's a little known pregnancy symptom for you: extreme motion sickness. I get sick when I drive now. Mum said to ask the obstetricians about it, and they suggested that not being pregnant would be a good solution.)

I need to get some sun though. Luckily, stone fruits are coming into season, so I am motivated to head for the shops. And if I sleep well, perhaps to go into the city and have Spice I Am with Andrew on his way home. Time for a goodly bit of fire.

Originally posted at http://puzzling.org/logs/diary/2009/November/13/20091113

Tags: , , , , , ,

puzzlement
[info]puzzlement
Add to Memories
Tell a Friend

I've held off on mentioning this here, although it's not exactly a secret, that I'm group blogging elsewhere; I wanted to wait until there was something to see at both sites. You can now find me regularly at Geek Feminism (well, possibly only regularly before my child is born), and occasionally at Hoyden About Town. I won't in general be cross-posting things to puzzling.org, although I might do so occasionally if it's relevant to my usual topics here. At some point I may set up a feed of my posts in various places in case you are in need of the full Mary experience. Not that I'd suggest skipping the other GF or HAT authors...

Originally posted at http://puzzling.org/logs/thoughts/2009/November/9/mary-elsewhere

Tags:

jcalderone
[info]jcalderone
Add to Memories
Tell a Friend

Welcome to the 14th installment of "Twisted Web in 60 seconds". In many of the previous installments, I've demonstrated how to serve content by using existing resource classes or implementing new ones. In this installment, I'll demonstrate how you can use Twisted Web's basic or digest HTTP authentication to control access to these resources.

Guard, the Twisted Web module which provides most of the APIs which will be used in this example, helps you to add authentication and authorization to a resource hierarchy. It does this by providing a resource which implements getChild to return a dynamically selected resource. The selection is based on the authentication headers in the request. If those headers indicate the request is made on behalf of Alice, then Alice's resource will be returned. If they indicate it was made on behalf of Bob, his will be returned. If the headers contain invalid credentials, an error resource is returned. Whatever happens, once this resource is returned, URL traversal continues as normal from that resource.

The resource which implements this is HTTPAuthSessionWrapper, though it is directly is directly responsible for very little of the process. It will extract headers from the request and hand them off to a credentials factory to parse them according to the appropriate standards (eg HTTP Authentication: Basic and Digest Access Authentication) and then it hands the resulting credentials object off to a portal, the core of Twisted Cred, a system for uniform handling of authentication and authorization. I am not going to discuss Twisted Cred in much depth here. To make use of it with Twisted Web, the only thing you really need to know is how to implement a realm.

You need to implement a realm because the realm is the object which actually decides which resources are used for which users. This can be as complex or as simple as it suitable for your application. For this example, I'll keep it very simple: each user will have a resource which is a static file listing of the public_html directory in their UNIX home directory. First, I need to import implements from zope.interface and IRealm from twisted.cred.portal. Together these will let me mark this class as a realm (this is mostly - but notentirely - a documentation thing). I'll also need File for the actual implementation later.

  from zope.interface import implements

 from twisted.cred.portal import IRealm
 from twisted.web.static import File

 class PublicHTMLRealm(object):
     implements(IRealm)

A realm only needs to implement one method, requestAvatar. This is called after any successful authentication attempt (ie, Alice supplied the right password). Its job is to return the avatar for the user who succeeded in authenticating. An avatar is just an object that represents a user. In this case, it will be a File. In general, with Guard, the avatar must be a resource of some sort.

      def requestAvatar(self, avatarId, mind, *interfaces):
         if IResource in interfaces:
             return (IResource, File("/home/%s/public_html" % (avatarId,)), lambda: None)
         raise NotImplementedError()

A few notes on this method:

  • The avatarId parameter is essentially the username. It's the job of some other code to extract the username from the request headers and make sure it gets passed here.
  • The mind is always None when writing a realm to be used with Guard. You can ignore it until you want to write a realm for something else.
  • Guard always passed IResource for the interfaces parameter. If interfaces only contains interfaces your code doesn't understand, raising NotImplementedError is the thing to do, as above. You'll only need to worry about getting a different interface when you write a realm for something other than Guard.
  • If you want to track when a user logs out, that's what the last element of the returned tuple is for. It will be called when this avatar logs out. lambda: None is the idiomatic no-op logout function.
  • Notice that I have written the path handling code in this example very poorly. This example may be vulnerable to certain unintentional information disclosure attacks. This sort of problem is exactly the reason FilePath exists. However, that's an example for another day...

We're almost ready to set up the resource for this example. To create an HTTPAuthSessionWrapper, though, we need two things. First, a portal, which requires the realm above, plus at least one credentials checker:

  from twisted.cred.portal import Portal
 from twisted.cred.checkers import FilePasswordDB

 portal = Portal(PublicHTMLRealm(), [FilePasswordDB('httpd.password')])

FilePasswordDB is that credentials checker I mentioned. It knows how to read passwd(5)-style (loosely) files to check credentials against. It is responsible for the authentication work after HTTPAuthSessionWrapper extracts the credentials from the request.

Next we need either BasicCredentialFactory or DigestCredentialFactory. The former knows how to challenge HTTP clients to do basic authentication; the latter, digest authentication. I'll use digest here:

  from twisted.web.guard import DigestCredentialFactory

 credentialFactory = DigestCredentialFactory("md5", "example.org")

The two parameters to this constructor are the hash algorithm and the http authentication realm which will be used. The only other valid hash algorithm is "sha" (but be careful, MD5 is more widely supported than SHA). The http authentication realm is mostly just a string that is presented to the user to let them know why they're authenticating (you can read more about this in the RFC).

With those things created, we can finally instantiate HTTPAuthSessionWrapper:

  from twisted.web.guard import HTTPAuthSessionWrapper

 resource = HTTPAuthSessionWrapper(portal, [credentialFactory])

There's just one last thing that needs to be done here. When I introduced rpy scripts, I mentioned that they're evaluated in an unusual context. This is the first example which actually needs to take this into account. It so happens that DigestCredentialFactory instances are actually stateful. Authentication will only succeed if the same instance is used to generate challenges and examine the responses to those challenges. However, the normal mode of operation for an rpy script is for it to be re-executed for every request. This leads to a new DigestCredentialFactory being created for every request, preventing any authentication attempt from ever succeeding.

There are two ways to deal with this. First, the better of the two ways, I could move almost all of the code into a real Python module, including the code which instantiates the DigestCredentialFactory. This would make ensure the same instance was used for every request. Second, the easier of the two ways, I could add a call to cache to the beginning of the rpy script:

  cache()

cache is part of the globals of any rpy script, so you don't need to import it (it's okay to be cringing at this point). Calling cache makes Twisted re-use the result of the first evaluation of the rpy script for subsequent requests too. Just what I want in this case.

Here's the complete example (with imports re-arranged to the more conventional style):

cache()

from zope.interface import implements

from twisted.cred.portal import IRealm, Portal
from twisted.cred.checkers import FilePasswordDB
from twisted.web.static import File
from twisted.web.resource import IResource
from twisted.web.guard import HTTPAuthSessionWrapper, DigestCredentialFactory

class PublicHTMLRealm(object):
   implements(IRealm)

   def requestAvatar(self, avatarId, mind, *interfaces):
       if IResource in interfaces:
           return (IResource, File("/home/%s/public_html" % (avatarId,)), lambda: None)
       raise NotImplementedError()

portal = Portal(PublicHTMLRealm(), [FilePasswordDB('httpd.password')])

credentialFactory = DigestCredentialFactory("md5", "localhost:8080")
resource = HTTPAuthSessionWrapper(portal, [credentialFactory])

And voila, a password-protected per-user Twisted Web server.

I've gotten several requests to write something about sessions, so there's a good chance that's what you'll find in the next installment.

Tags: , , , , , ,

jcalderone
[info]jcalderone
Add to Memories
Tell a Friend

As of Monday, the 9th, I will be considering opportunities for short term consulting and contract work. Please feel free to contact me if you have a software challenge to tackle, particularly if it involves one or more of Python, Twisted, networking, event-driven architectures, massive scaling, or open source software.

Immediately following the demise of Divmod this summer, I took a job at a major international corporation. A number of factors conspired to make this decision non-viable in the long term. Today I gave notice. I'm excited to be able to get back to doing what I love - solving challenging, interesting problems in a flexible, open environment.

One of the other things I've been unable to do since even before Divmod's end is commit serious time to Twisted development and maintenance. This is something else I'm looking forward to re-engaging in. I made a sizable dent in Twisted's open ticket count last fall and winter, thanks to funding from the Twisted Software Foundation (in turn thanks to all of the Twisted founding sponsors). I'll be able to continue this work thanks to this year's sponsors (visible on the front page of the Twisted site), though perhaps not to the same extent. If you'd like to help out in this regard, become a sponsor! All donations are useful and appreciated!

Tags: ,

puzzlement
[info]puzzlement
Add to Memories
Tell a Friend

I've often wondered about why going from a 25℃ day to a 35℃ day is a kind of death, but 35℃ to 45℃ (well, more usually 41℃ or so, I've only ever experienced one day above 45℃, even if it does count for extra spending that morning in direct sunlight clad in a 5mm scuba wetsuit that I bought for use in winter) is a difference in kind only. I gather most of our extremely unseasonable days come in from the desert though, so I suppose the difference is humidity. Mid-summer in Sydney can turn on 38℃ and humid in season, but the desert will send 38℃ and dry out of it.

Today was a desert day, forecast 35℃, actual temperatures closer to 39℃, but dry and windy. It was not unsurvivable, and I say this from the perspective of third trimester, usually proclaimed as a lifetime peak of heat intolerance. But I am yet to be tested against humidity and heat together.

I'm going to watch the forecasts though, and carry a water bottle around for hot days, because a train got stuck on the Harbour Bridge for 40 minutes today and 40 minutes in unairconditioned railway carriages full of angry people will make me pretty ill now, but without water I'd be in big trouble.

The other great thing about desert days is that they're always broken with southerlies. Well, great for me because I can sit around and enjoy the small adrenaline rush that comes with having the weather try and break into my house. Less great for anyone fighting the fires that start on desert days, although it doesn't seem that today was too bad in that respect.

We beached on Sunday. My upbringing has misled me: my family were never at the beach between 11am and 3:30pm. You wake up with the beach. You say good afternoon with the beach. You don't stay there for the peak of the UV index. So I'm always mildly surprised to be sitting in the sun with cheerful pale skinned people at noon. As best I can tell the surf is always pretty substantial at Bronte, and I don't trust myself with my new planetary shape in the surf, so I stuck to the giant rock pools and the ocean bath. Being in the water was astoundingly pleasant; being out of it must be getting more uncomfortable than I had realised.

Andrew said that the surf was good quality, but it was typical Sydney: the flags for safe swimming were all of about five metres apart, and there was a rip down the middle of the beach twice as wide as that (Pete was annoyed, the bits without waves always look more appealing). There must have been a decent current too, someone got swept right down the beach to the south. Turns out if you shout loudly enough, essentially all of Bronte will hear you. (A lifesaver went out efficiently on a big blue longboard well before he was at serious risk of being tossed onto the rocks.)

It feels like I should slow my life down, and generally this year has not been as hectic as last, one upside of many of my friends moving away I suppose. But for example this weekend, on top of the beach on Sunday we had an infant care class on Saturday (lots of videos of babies grizzling) and then went to Jamie and Lisa's Halloween/birthday party. We decided to rent a car for the Saturday extravaganza. I can see why people with small cars drive everywhere; if you regard the purchase and upkeep of the car as a sunk cost, the fuel makes it considerably cheaper than public transport. We spent $5.77 on fuel for the day. The downside was parking in Pyrmont. Most of the parking is 1 or 2 hours, 24 hours a day, due to the nearby casino. We eventually wedged our teeny rental Getz in half a car spot.

I was pretty lazy about my costume this year. Partly it's just hard to top Andrew's effort in cutting off more than a foot of hair for a party in 2006. But I'm also trying to limit the number of outfits I buy that are designed to fit me and my 40cm passenger. If I could have found a cheap way to go as Saturn I would have. (For bonus points, Janus is a moon of Saturn.) Anyway, now Janus has some pirate gear for his dress-up box.

Originally posted at http://puzzling.org/logs/diary/2009/November/3/20091103

Tags: , , , , ,

jcalderone
[info]jcalderone
Add to Memories
Tell a Friend

  • The Player of Games. Iain Banks.

  • The State of the Art. Iain Banks.

  • Use of Weapons. Iain Banks.

  • Excession. Iain Banks.

  • Inversions. Iain Banks.

  • The Planck Dive. Greg Egan.

  • The Name of the Wind. Patrick Rothfuss.

  • Red Seas Under Red Skies. Scott Lynch.

Tags:

jcalderone
[info]jcalderone
Add to Memories
Tell a Friend
A bunch of us carved pumpkins for Halloween, and Ying was thoughtful enough to bring along her very nice camera and got some nice shots.

Tags: , ,

deeptape
[info]deeptape
Add to Memories
Tell a Friend
photo.jpg

deeptape
[info]deeptape
Add to Memories
Tell a Friend
photo.jpg

profile
Glyph Lefkowitz
User: [info]glyf
Name: Glyph Lefkowitz
calendar
Back April 2008
12345
6789101112
13141516171819
20212223242526
27282930
page summary
tags